亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Step by Step:Linux C多線程編程入門(基本API

系統 2034 0

Step by Step:Linux C多線程編程入門(基本API及多線程的同步與互斥)

介紹:什么是線程,線程的優點是什么

線程在Unix系統下,通常被稱為輕量級的進程,線程雖然不是進程,但卻可以看作是Unix進程的表親,同一進程中的多條線程將 共享該進程中的全部系統資源,如虛擬地址空間,文件描述符和信號處理等等 。但同一進程中的多個線程 有各自的調用棧(call stack),自己的寄存器環境(register context),自己的線程本地存儲(thread-local storage) 。 一個進程可以有很多線程,每條線程并行執行不同的任務。

線程可以提高應用程序在多核環境下處理諸如文件I/O或者socket I/O等會產生堵塞的情況的表現性能。在Unix系統中,一個進程包含很多東西,包括可執行程序以及一大堆的諸如文件描述符地址空間等資源。在很多情況下,完成相關任務的不同代碼間需要交換數據。如果采用多進程的方式,那么通信就需要在用戶空間和內核空間進行頻繁的切換,開銷很大。但是如果使用多線程的方式,因為可以使用共享的全局變量,所以線程間的通信(數據交換)變得非常高效。

Hello World(線程創建、結束、等待)

創建線程 pthread_create

線程創建函數包含四個變量,分別為: 1. 一個線程變量名,被創建線程的標識 2. 線程的屬性指針,缺省為NULL即可 3. 被創建線程的程序代碼 4. 程序代碼的參數 For example: - pthread_t thrd1; - pthread_attr_t? attr; - void thread_function(void? argument); - char *some_argument;

pthread_create(&thrd1, NULL, (void *)&thread_function, (void *) &some_argument);

結束線程 pthread_exit

線程結束調用實例: pthread_exit(void *retval); ?//retval用于存放線程結束的退出狀態

線程等待 pthread_join

pthread_create調用成功以后,新線程和老線程誰先執行,誰后執行用戶是不知道的,這一塊取決與操作系統對線程的調度,如果我們需要等待指定線程結束,需要使用pthread_join函數,這個函數實際上類似與多進程編程中的waitpid。 舉個例子,以下假設 A 線程調用 pthread_join 試圖去操作B線程,該函數將A線程阻塞,直到B線程退出,當B線程退出以后,A線程會收集B線程的返回碼。 該函數包含兩個參數:

  • pthread_t th //th是要等待結束的線程的標識
  • void **thread_return //指針thread_return指向的位置存放的是終止線程的返回狀態。

調用實例: pthread_join(thrd1, NULL);

example1:

        
           1
        
        
          /*
        
        
          ************************************************************************


        
        
           2
        
        
              > File Name: thread_hello_world.c 


        
        
           3
        
        
              > Author: couldtt(fyby)


        
        
           4
        
        
              > Mail:  fuyunbiyi@gmail.com


        
        
           5
        
        
              > Created Time: 2013年12月14日 星期六 11時48分50秒


        
        
           6
        
        
           ***********************************************************************
        
        
          */
        
        
           7
        
        
           8
        
         #include <stdio.h>


        
           9
        
         #include <stdlib.h>


        
          10
        
         #include <pthread.h>


        
          11
        
        
          12
        
        
          void
        
         print_message_function (
        
          void
        
         *
        
          ptr);


        
        
          13
        
        
          14
        
        
          int
        
        
           main()


        
        
          15
        
        
          {


        
        
          16
        
        
          int
        
        
           tmp1, tmp2;


        
        
          17
        
        
          void
        
         *
        
          retval;


        
        
          18
        
        
              pthread_t thread1, thread2;


        
        
          19
        
        
          char
        
         *message1 = 
        
          "
        
        
          thread1
        
        
          "
        
        
          ;


        
        
          20
        
        
          char
        
         *message2 = 
        
          "
        
        
          thread2
        
        
          "
        
        
          ;


        
        
          21
        
        
          22
        
        
          int
        
        
           ret_thrd1, ret_thrd2;


        
        
          23
        
        
          24
        
             ret_thrd1 = pthread_create(&thread1, NULL, (
        
          void
        
         *)&print_message_function, (
        
          void
        
         *
        
          ) message1);


        
        
          25
        
             ret_thrd2 = pthread_create(&thread2, NULL, (
        
          void
        
         *)&print_message_function, (
        
          void
        
         *
        
          ) message2);


        
        
          26
        
        
          27
        
        
          //
        
        
           線程創建成功,返回0,失敗返回失敗號
        
        
          28
        
        
          if
        
         (ret_thrd1 != 
        
          0
        
        
          ) {


        
        
          29
        
                 printf(
        
          "
        
        
          線程1創建失敗\n
        
        
          "
        
        
          );


        
        
          30
        
             } 
        
          else
        
        
           {


        
        
          31
        
                 printf(
        
          "
        
        
          線程1創建成功\n
        
        
          "
        
        
          );


        
        
          32
        
        
              }


        
        
          33
        
        
          34
        
        
          if
        
         (ret_thrd2 != 
        
          0
        
        
          ) {


        
        
          35
        
                 printf(
        
          "
        
        
          線程2創建失敗\n
        
        
          "
        
        
          );


        
        
          36
        
             } 
        
          else
        
        
           {


        
        
          37
        
                 printf(
        
          "
        
        
          線程2創建成功\n
        
        
          "
        
        
          );


        
        
          38
        
        
              }


        
        
          39
        
        
          40
        
        
          //
        
        
          同樣,pthread_join的返回值成功為0
        
        
          41
        
             tmp1 = pthread_join(thread1, &
        
          retval);


        
        
          42
        
             printf(
        
          "
        
        
          thread1 return value(retval) is %d\n
        
        
          "
        
        , (
        
          int
        
        
          )retval);


        
        
          43
        
             printf(
        
          "
        
        
          thread1 return value(tmp) is %d\n
        
        
          "
        
        
          , tmp1);


        
        
          44
        
        
          if
        
         (tmp1 != 
        
          0
        
        
          ) {


        
        
          45
        
                 printf(
        
          "
        
        
          cannot join with thread1\n
        
        
          "
        
        
          );


        
        
          46
        
        
              }


        
        
          47
        
             printf(
        
          "
        
        
          thread1 end\n
        
        
          "
        
        
          );


        
        
          48
        
        
          49
        
             tmp2 = pthread_join(thread1, &
        
          retval);


        
        
          50
        
             printf(
        
          "
        
        
          thread2 return value(retval) is %d\n
        
        
          "
        
        , (
        
          int
        
        
          )retval);


        
        
          51
        
             printf(
        
          "
        
        
          thread2 return value(tmp) is %d\n
        
        
          "
        
        
          , tmp1);


        
        
          52
        
        
          if
        
         (tmp2 != 
        
          0
        
        
          ) {


        
        
          53
        
                 printf(
        
          "
        
        
          cannot join with thread2\n
        
        
          "
        
        
          );


        
        
          54
        
        
              }


        
        
          55
        
             printf(
        
          "
        
        
          thread2 end\n
        
        
          "
        
        
          );


        
        
          56
        
        
          57
        
        
          }


        
        
          58
        
        
          59
        
        
          void
        
         print_message_function( 
        
          void
        
         *
        
          ptr ) {


        
        
          60
        
        
          int
        
         i = 
        
          0
        
        
          ;


        
        
          61
        
        
          for
        
         (i; i<
        
          5
        
        ; i++
        
          ) {


        
        
          62
        
                 printf(
        
          "
        
        
          %s:%d\n
        
        
          "
        
        , (
        
          char
        
         *
        
          )ptr, i);


        
        
          63
        
        
              }


        
        
          64
        
         }
      

?

編譯

gcc thread_hello_world.c -otest -lpthread ?一定要加上 -lpthread ,要不然會報錯,因為源代碼里引用了pthread.h里的東西,所以在gcc進行鏈接的時候,必須要找到這些庫的二進制實現代碼。

運行結果

?結果分析: 1.這段程序我運行了兩次,可以看到,兩次的運行結果是不一樣的,從而說明, 新線程和老線程誰先執行,誰后執行用戶是不知道的,這一塊取決與操作系統對線程的調度 。 2.另外,我們看到,在thread2的join結果出現了錯誤,打印出 cannot join with thread2 其實這個是個小錯誤,因為,我pthread_join傳進去的th是thread1,在上面的結果中,thread1早已經結束了,所以我們再次等待thread1結束肯定會出現無法取到狀態的錯誤的。 3.pthread_join(thread1, &retval)確實等待了thread1的結束,我們看到,在 print_message_function 函數循環了5遍結束以后,才打印出thread1 end

這是一個非常簡單的例子,hello world級別的,只是用來演示Linux下C多線程的使用,在實際應用中,由于多個線程往往會訪問共享的資源(典型的是訪問同一個全局變量),因此多個縣城間存在著競爭的關系,這就需要對多個線程進行同步,對其訪問的數據予以保護。

多線程的同步與互斥

方式一:鎖

  • 在主線程中初始化鎖為解鎖狀態
    • pthread_mutex_t mutex;
    • pthread_mutex_init(&mutex, NULL);
  • 在編譯時初始化鎖為解鎖狀態
    • 鎖初始化 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • 訪問對象時的加鎖操作與解鎖操作
    • 加鎖 pthread_mutex_lock(&mutex)
    • 釋放鎖 pthread_mutex_unlock(&mutex)
不加鎖,數據不同步

我們先來看一個不加鎖,多個線程訪問同一段數據的程序。

        
           1
        
        
          /*
        
        
          ************************************************************************


        
        
           2
        
        
              > File Name: no_mutex.c


        
        
           3
        
        
              > Author: couldtt(fyby)


        
        
           4
        
        
              > Mail: fuyunbiyi@gmail.com


        
        
           5
        
        
              > Created Time: 2013年12月15日 星期日 17時52分24秒


        
        
           6
        
        
           ***********************************************************************
        
        
          */
        
        
           7
        
        
           8
        
         #include <stdio.h>


        
           9
        
         #include <stdlib.h>


        
          10
        
         #include <pthread.h>


        
          11
        
        
          12
        
        
          int
        
         sharedi = 
        
          0
        
        
          ;


        
        
          13
        
        
          void
        
         increse_num(
        
          void
        
        
          );


        
        
          14
        
        
          15
        
        
          int
        
        
           main(){


        
        
          16
        
        
          int
        
        
           ret;


        
        
          17
        
        
              pthread_t thrd1, thrd2, thrd3;


        
        
          18
        
        
          19
        
             ret = pthread_create(&thrd1, NULL, (
        
          void
        
         *
        
          )increse_num, NULL);


        
        
          20
        
             ret = pthread_create(&thrd2, NULL, (
        
          void
        
         *
        
          )increse_num, NULL);


        
        
          21
        
             ret = pthread_create(&thrd3, NULL, (
        
          void
        
         *
        
          )increse_num, NULL);


        
        
          22
        
        
          23
        
        
              pthread_join(thrd1, NULL);


        
        
          24
        
        
              pthread_join(thrd2, NULL);


        
        
          25
        
        
              pthread_join(thrd3, NULL);


        
        
          26
        
        
          27
        
             printf(
        
          "
        
        
          sharedi = %d\n
        
        
          "
        
        
          , sharedi);


        
        
          28
        
        
          29
        
        
          return
        
        
          0
        
        
          ;


        
        
          30
        
        
          31
        
        
          }


        
        
          32
        
        
          33
        
        
          void
        
         increse_num(
        
          void
        
        
          ) {


        
        
          34
        
        
          long
        
        
           i,tmp;


        
        
          35
        
        
          for
        
        (i=
        
          0
        
        ; i<=
        
          100000
        
        ; i++
        
          ) {


        
        
          36
        
                 tmp =
        
           sharedi;


        
        
          37
        
                 tmp = tmp + 
        
          1
        
        
          ;


        
        
          38
        
                 sharedi =
        
           tmp;


        
        
          39
        
        
              }


        
        
          40
        
         }
      

?

編譯

gcc no_mutex.c -onomutex -lpthread

運行分析

從上圖可知,我們no_mutex每次的運行結果都不一致,而且,運行結果也不符合我們的預期,出現了錯誤的結果。 原因就是三個線程競爭訪問全局變量sharedi,并且都沒有進行相應的同步。

舉個例子,當線程thrd1訪問到sharedi的時候,sharedi的值是1000,然后線程thrd1將sharedi的值累加到了1001,可是線程thrd2取到sharedi的時候,sharedi的值是1000,這時候線程thrd2對sharedi的值進行加1操作,使其變成了1001,可是這個時候,sharedi的值已經被線程thrd1加到1001了,然而,thrd2并不知道,所以又將sharedi的值賦為了1001,從而導致了結果的錯誤。

這樣,我們就需要一個線程互斥的機制,來保護sharedi這個變量,讓同一時刻,只有一個線程能夠訪問到這個變量,從而使它的值能夠保證正確的變化。

加鎖,數據同步

通過加鎖,保證sharedi變量在進行變更的時候,只有一個線程能夠取到,并在在該線程對其進行操作的時候,其它線程無法對其進行訪問。

        
           1
        
        
          /*
        
        
          ************************************************************************


        
        
           2
        
        
              > File Name: mutex.c 


        
        
           3
        
        
              > Author: couldtt(fyby)


        
        
           4
        
        
              > Mail: fuyunbiyi@gmail.com 


        
        
           5
        
        
              > Created Time: 2013年12月15日 星期日 17時52分24秒


        
        
           6
        
        
           ***********************************************************************
        
        
          */
        
        
           7
        
        
           8
        
         #include <stdio.h>


        
           9
        
         #include <stdlib.h>


        
          10
        
         #include <pthread.h>


        
          11
        
        
          12
        
        
          int
        
         sharedi = 
        
          0
        
        
          ;


        
        
          13
        
        
          void
        
         increse_num(
        
          void
        
        
          );


        
        
          14
        
        
          15
        
         pthread_mutex_t mutex =
        
           PTHREAD_MUTEX_INITIALIZER;


        
        
          16
        
        
          17
        
        
          int
        
        
           main(){


        
        
          18
        
        
          int
        
        
           ret;


        
        
          19
        
        
              pthread_t thrd1, thrd2, thrd3;


        
        
          20
        
        
          21
        
             ret = pthread_create(&thrd1, NULL, (
        
          void
        
         *
        
          )increse_num, NULL);


        
        
          22
        
             ret = pthread_create(&thrd2, NULL, (
        
          void
        
         *
        
          )increse_num, NULL);


        
        
          23
        
             ret = pthread_create(&thrd3, NULL, (
        
          void
        
         *
        
          )increse_num, NULL);


        
        
          24
        
        
          25
        
        
              pthread_join(thrd1, NULL);


        
        
          26
        
        
              pthread_join(thrd2, NULL);


        
        
          27
        
        
              pthread_join(thrd3, NULL);


        
        
          28
        
        
          29
        
             printf(
        
          "
        
        
          sharedi = %d\n
        
        
          "
        
        
          , sharedi);


        
        
          30
        
        
          31
        
        
          return
        
        
          0
        
        
          ;


        
        
          32
        
        
          33
        
        
          }


        
        
          34
        
        
          35
        
        
          void
        
         increse_num(
        
          void
        
        
          ) {


        
        
          36
        
        
          long
        
        
           i,tmp;


        
        
          37
        
        
          for
        
        (i=
        
          0
        
        ; i<=
        
          100000
        
        ; i++
        
          ) {


        
        
          38
        
        
          /*
        
        
          加鎖
        
        
          */
        
        
          39
        
        
          if
        
         (pthread_mutex_lock(&mutex) != 
        
          0
        
        
          ) {


        
        
          40
        
                    perror(
        
          "
        
        
          pthread_mutex_lock
        
        
          "
        
        
          );


        
        
          41
        
        
                     exit(EXIT_FAILURE);


        
        
          42
        
        
                  }


        
        
          43
        
                 tmp =
        
           sharedi;


        
        
          44
        
                 tmp = tmp + 
        
          1
        
        
          ;


        
        
          45
        
                 sharedi =
        
           tmp;


        
        
          46
        
        
          /*
        
        
          解鎖鎖
        
        
          */
        
        
          47
        
        
          if
        
         (pthread_mutex_unlock(&mutex) != 
        
          0
        
        
          ) {


        
        
          48
        
                     perror(
        
          "
        
        
          pthread_mutex_unlock
        
        
          "
        
        
          );


        
        
          49
        
        
                      exit(EXIT_FAILURE);


        
        
          50
        
        
                  }


        
        
          51
        
        
              }


        
        
          52
        
         }
      

?

結果分析

加鎖

這一次,我們的結果是正確的,鎖有效得保護了我們的數據安全。然而:

  1. 鎖保護的并不是我們的共享變量(或者說是共享內存),對于共享的內存而言,用戶是無法直接對其保護的,因為那是物理內存,無法阻止其他程序的代碼訪問。事實上,鎖之所以對關鍵區域進行了保護,在本例中,是因為所有線程都遵循了一個規則,那就是在進入關鍵區域錢加 同一把 鎖,在退出關鍵區域錢釋放 同一把

  2. 我們從上述運行結果中可以看到,加鎖是會帶來額外的開銷的,加鎖的代碼其運行速度,明顯比不加鎖的要慢一些,所以,在使用鎖的時候,要合理,在不需要對關鍵區域進行保護的場景下,我們便不要畫蛇添足,為其加鎖了

方式二:信號量

鎖有一個很明顯的缺點,那就是它 只有兩種狀態 :鎖定與不鎖定。

信號量本質上是一個非負數的整數計數器,它也被用來控制對公共資源的訪問。當公共資源增加的時候,調用信號量增加函數sem_post()對其進行增加,當公共資源減少的時候,調用函數sem_wait()來減少信號量。其實,我們是可以把鎖當作一個0-1信號量的。

它們是在 /usr/include/semaphore.h 中進行定義的,信號量的數據結構為sem_t, 本質上,它是一個long型整數

相關函數

在使用semaphore之前,我們需要先引入頭文件 #include <semaphore.h>

  • 初始化信號量:? int sem_init(sem_t *sem, int pshared, unsigned int value);
    • 成功返回0,失敗返回-1
    • 參數
    • sem:指向信號量結構的一個指針
    • pshared: 不是0的時候,該信號量在進程間共享,否則只能為當前進程的所有線程們共享
    • value:信號量的初始值
  • 信號量減1操作,當sem=0的時候該函數會堵塞? int sem_wait(sem_t *sem);
    • 成功返回0,失敗返回-1
    • 參數
    • sem:指向信號量的一個指針
  • 信號量加1操作? int sem_post(sem_t *sem);
    • 參數與返回同上
  • 銷毀信號量? int sem_destroy(sem_t *sem);
    • 參數與返回同上
代碼示例
        
           1
        
        
          /*
        
        
          ************************************************************************


        
        
           2
        
        
              > File Name: sem.c


        
        
           3
        
        
              > Author: couldtt(fyby)


        
        
           4
        
        
              > Mail: fuyunbiyi@gmail.com 


        
        
           5
        
        
              > Created Time: 2013年12月15日 星期日 19時25分08秒


        
        
           6
        
        
           ***********************************************************************
        
        
          */
        
        
           7
        
        
           8
        
         #include <stdio.h>


        
           9
        
         #include <unistd.h>


        
          10
        
         #include <pthread.h>


        
          11
        
         #include <semaphore.h>


        
          12
        
        
          13
        
        
          #define
        
         MAXSIZE 10


        
          14
        
        
          15
        
        
          int
        
        
           stack[MAXSIZE];


        
        
          16
        
        
          int
        
         size = 
        
          0
        
        
          ;


        
        
          17
        
        
          sem_t sem;


        
        
          18
        
        
          19
        
        
          //
        
        
           生產者
        
        
          20
        
        
          void
        
         provide_data(
        
          void
        
        
          ) {


        
        
          21
        
        
          int
        
        
           i;


        
        
          22
        
        
          for
        
         (i=
        
          0
        
        ; i< MAXSIZE; i++
        
          ) {


        
        
          23
        
                 stack[i] =
        
           i;


        
        
          24
        
                 sem_post(&sem); 
        
          //
        
        
          為信號量加1
        
        
          25
        
        
              }


        
        
          26
        
        
          }


        
        
          27
        
        
          28
        
        
          //
        
        
           消費者
        
        
          29
        
        
          void
        
         handle_data(
        
          void
        
        
          ) {


        
        
          30
        
        
          int
        
        
           i;


        
        
          31
        
        
          while
        
        ((i = size++) <
        
           MAXSIZE) {


        
        
          32
        
                 sem_wait(&
        
          sem);


        
        
          33
        
                 printf(
        
          "
        
        
          乘法: %d X %d = %d\n
        
        
          "
        
        , stack[i], stack[i], stack[i]*
        
          stack[i]);


        
        
          34
        
                 sleep(
        
          1
        
        
          );


        
        
          35
        
        
              }


        
        
          36
        
        
          }


        
        
          37
        
        
          38
        
        
          int
        
         main(
        
          void
        
        
          ) {


        
        
          39
        
        
          40
        
        
              pthread_t provider, handler;


        
        
          41
        
        
          42
        
             sem_init(&sem, 
        
          0
        
        , 
        
          0
        
        ); 
        
          //
        
        
          信號量初始化
        
        
          43
        
             pthread_create(&provider, NULL, (
        
          void
        
         *
        
          )handle_data, NULL);


        
        
          44
        
             pthread_create(&handler, NULL, (
        
          void
        
         *
        
          )provide_data, NULL);


        
        
          45
        
        
              pthread_join(provider, NULL);


        
        
          46
        
        
              pthread_join(handler, NULL);


        
        
          47
        
             sem_destroy(&sem); 
        
          //
        
        
          銷毀信號量
        
        
          48
        
        
          49
        
        
          return
        
        
          0
        
        
          ;


        
        
          50
        
         }
      

?

運行結果:

因為信號量機制的存在,所以代碼在handle_data的時候,如果sem_wait(&sem)時,sem為0,那么代碼會堵塞在sem_wait上面,從而避免了在stack中訪問錯誤的index而使整個程序崩潰。

參考資料

?
?

Step by Step:Linux C多線程編程入門(基本API及多線程的同步與互斥)


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美一级特黄aaa大片 | 国产伦精品一区二区三区在线观看 | 五月天婷婷激情网 | 福利午夜在线 | 成年女人视频免费观看一 | 超清中文乱码字幕在线观看 | 精品黑人一区二区三区 | 999毛片免费观看 | 成人二区 | 久久免费视频99 | 亚洲一区二区三区在线免费观看 | 亚洲精品综合网 | 亚洲精品久久玖玖玖玖 | 日韩精品欧美国产精品亚 | 国产精品视频久 | 国产精品在线观看 | 免费国产视频 | 人人澡人人澡人人看欧美 | 九九热国产 | 91热久久免费精品99 | 日本免费小视频 | 我要看欧美精品一级毛片 | 亚洲欧美日韩国产综合久 | 国产在线观看自拍 | 国产福利视频在线观看 | 爱爱视频免费在线观看 | 国产精品白丝喷水在线观看 | 成人久久18免费网站游戏 | 日本一区二区三区中文字幕 | 91手机看片国产福利精品 | 特级全黄一级毛片免费 | 伊人色色网 | 国产亚洲精品一区二区在线观看 | 韩国精品欧美一区二区三区 | 夜夜操天天插 | 97视频免费播放观看在线视频 | 四虎永久免费网站入口2020 | 老司机午夜影院 | 宅男在线看片 | 国产亚洲漂亮白嫩美女在线 | 中文国产日韩欧美视频 |