1. 程式人生 > >多執行緒程式設計同步問題

多執行緒程式設計同步問題

實現機制有:1 互斥鎖 2 訊號量 3 條件變數

一、 為什麼要用多執行緒技術?

1、避免阻塞,大家知道,單個程序只有一個主執行緒,當主執行緒阻塞的時候,整個程序也就阻塞了,無法再去做其它的一些功能了。

2、避免CPU空轉,應用程式經常會涉及到RPC,資料庫訪問,磁碟IO等操作,這些操作的速度比CPU慢很多,而在等待這些響應時,CPU卻不能去處理新的請求,導致這種單執行緒的應用程式效能很差。

3、提升效率,一個程序要獨立擁有4GB的虛擬地址空間,而多個執行緒可以共享同一地址空間,執行緒的切換比程序的切換要快得多。

下面給出個多執行緒程式,一個最簡單的模擬售票系統,程式碼如下:

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. void *ticketsell1(void *);  
  4. void *ticketsell2(void *);  
  5. int tickets = 20;  
  6. int main()  
  7. {  
  8.     pthread_t id1,id2;  
  9.     int error;  
  10.     error = pthread_create(&id1, NULL, ticketsell1, NULL);  
  11.     if(error != 0)  
  12.     {  
  13.         printf("pthread is not created!\n");  
  14.         return
     -1;  
  15.     }  
  16.     error = pthread_create(&id2, NULL, ticketsell2, NULL);  
  17.     if(error != 0)  
  18.     {  
  19.         printf("pthread is not created!\n");  
  20.         return -1;  
  21.     }  
  22.     pthread_join(id1,NULL);  
  23.     pthread_join(id2,NULL);  
  24.     return 0;  
  25. }  
  26. void *ticketsell1(void *arg)  
  27. {  
  28.     while(1)  
  29.     {  
  30.         if(tickets > 0)  
  31.         {  
  32. //          usleep(1000);
  33.             printf("ticketse1 sells ticket:%d\n",tickets--);  
  34.         }  
  35.         else
  36.         {  
  37.             break;  
  38.         }  
  39.     }  
  40.     return (void *)0;  
  41. }  
  42. void *ticketsell2(void *arg)  
  43. {  
  44.     while(1)  
  45.     {  
  46.         if(tickets > 0)  
  47.         {  
  48. //          usleep(1000);
  49.             printf("ticketse2 sells ticket:%d\n",tickets--);  
  50.         }  
  51.         else
  52.         {  
  53.             break;  
  54.         }  
  55.     }  
  56.     return (void *)0;  
  57. }  

執行結果如下:

  1. [email protected]:~/qiang/mthread$ ./mthread1   
  2. ticketse2 sells ticket:20  
  3. ticketse2 sells ticket:19  
  4. ticketse2 sells ticket:18  
  5. ticketse2 sells ticket:17  
  6. ticketse2 sells ticket:16  
  7. ticketse2 sells ticket:15  
  8. ticketse2 sells ticket:14  
  9. ticketse2 sells ticket:13  
  10. ticketse2 sells ticket:12  
  11. ticketse2 sells ticket:11  
  12. ticketse2 sells ticket:10  
  13. ticketse2 sells ticket:9  
  14. ticketse2 sells ticket:8  
  15. ticketse2 sells ticket:7  
  16. ticketse2 sells ticket:6  
  17. ticketse2 sells ticket:4  
  18. ticketse2 sells ticket:3  
  19. ticketse2 sells ticket:2  
  20. ticketse2 sells ticket:1  
  21. ticketse1 sells ticket:5  

看到結果,我們發現時能正常賣票的,一部分連續是sel2,另一部分是ticketsel1;

此時,其實存在一個隱含的問題,就是執行緒間的切換,在單CPU系統中,CPU是有時間片時間,時間片到了,就要執行其它的執行緒,假設thread1執行到if裡面,但在printf執行前發生了執行緒切換,那麼會發生什麼呢?我們在這裡用usleep函式(放開程式中的usleep註釋行)進行強制模擬切換;

我們看看結果:

  1. [email protected]:~/qiang/mthread$ gcc -o mthread1 mthread1.c -lpthread  
  2. [email protected]:~/qiang/mthread$ ./mthread1   
  3. ticketse2 sells ticket:20  
  4. ticketse1 sells ticket:19  
  5. ticketse2 sells ticket:18  
  6. ticketse1 sells ticket:17  
  7. ticketse2 sells ticket:16  
  8. ticketse1 sells ticket:15  
  9. ticketse2 sells ticket:14  
  10. ticketse1 sells ticket:13  
  11. ticketse2 sells ticket:12  
  12. ticketse1 sells ticket:11  
  13. ticketse2 sells ticket:10  
  14. ticketse1 sells ticket:9  
  15. ticketse2 sells ticket:8  
  16. ticketse1 sells ticket:7  
  17. ticketse2 sells ticket:6  
  18. ticketse1 sells ticket:5  
  19. ticketse2 sells ticket:4  
  20. ticketse1 sells ticket:3  
  21. ticketse1 sells ticket:2  
  22. ticketse2 sells ticket:1  
  23. ticketse1 sells ticket:0  
  24. [email protected]:~/qiang/mthread$   

執行程式發現竟然有0號票被賣出了,這顯然是錯誤的!當thread1的if裡面發生執行緒切換時,thread2得到執行,把最後一張票賣了,此時thread1恢復執行,結果賣出了0號票,這裡我們需要的是火車票的票數資料對於所有執行緒而言是同步的,所以就要用到執行緒同步技術了。

三、  使用多執行緒的同步與互斥

1、多執行緒的同步方式有很多種,例如互斥鎖,條件變數,訊號量,讀寫鎖。先看看互斥鎖如何解決多執行緒之間的同步問題。程式用互斥鎖後如下:

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. void *ticketsell1(void *);  
  4. void *ticketsell2(void *);  
  5. int tickets = 20;  
  6. pthread_mutex_t mutex;  
  7. int main()  
  8. {  
  9.     pthread_t id1,id2;  
  10.     pthread_mutex_init(&mutex, NULL);//
  11.     int error;  
  12.     error = pthread_create(&id1, NULL, ticketsell1, NULL);  
  13.     if(error != 0)  
  14.     {  
  15.         printf("pthread is not created!\n");  
  16.         return -1;  
  17.     }  
  18.     error = pthread_create(&id2, NULL, ticketsell2, NULL);  
  19.     if(error != 0)  
  20.     {  
  21.         printf("pthread is not created!\n");  
  22.         return -1;  
  23.     }  
  24.     pthread_join(id1,NULL);  
  25.     pthread_join(id2,NULL);  
  26.     return 0;  
  27. }  
  28. void *ticketsell1(void *arg)  
  29. {  
  30.     while(1)  
  31.     {  
  32. 相關推薦

    no