成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一個多線程的簡單例子讓你看清線程調度的隨機性

開發 前端
多線程并發執行時有很多同學捋不清楚調度的隨機性會導致哪些問題,要知道如果訪問臨界資源不加鎖會導致一些突發情況發生甚至死鎖。

 [[348484]]

線程調度的幾個基本知識點

多線程并發執行時有很多同學捋不清楚調度的隨機性會導致哪些問題,要知道如果訪問臨界資源不加鎖會導致一些突發情況發生甚至死鎖。

關于線程調度,需要深刻了解以下幾個基礎知識點:

調度的最小單位是輕量級進程【比如我們編寫的hello world最簡單的C程序,執行時就是一個輕量級進程】或者線程;

每個線程都會分配一個時間片,時間片到了就會執行下一個線程;

線程的調度有一定的隨機性,無法確定什么時候會調度;

在同一個進程內,創建的所有線程除了線程內部創建的局部資源,進程創建的其他資源所有線程共享;比如:主線程和子線程都可以訪問全局變量,打開的文件描述符等。

實例

再多的理論不如一個形象的例子來的直接。

預期代碼時序

假定我們要實現一個多線程的實例,預期程序執行時序如下:

 

 

期待時序

 

 

期待的功能時序:

  1. 主進程創建子線程,子線程函數function();
  2. 主線程count自加,并分別賦值給value1,value2;
  3. 時間片到了后切換到子線程,子線程判斷value1、value2值是否相同,如果不同就打印信息value1,value2,count的值,但是因為主線程將count先后賦值給了value1,value2,所以value1,value2的值應該永遠不相同,所以不應該打印任何內容;
  4. 重復2、3步驟。

代碼1

好了,現在我們按照這個時序編寫代碼如下:

  1. 1 #include <stdio.h> 
  2.   2 #include <stdlib.h> 
  3.   3 #include <string.h> 
  4.   4 #include <pthread.h> 
  5.   5 #include <unistd.h> 
  6.   6  
  7.   7 unsigned int value1,value2, count=0; 
  8.   8 void *function(void *arg); 
  9.   9 int main(int argc,  char *argv[]) 
  10.  10 { 
  11.  11     pthread_t  a_thread; 
  12.  12  
  13.  13     if (pthread_create(&a_thread, NULLfunctionNULL) < 0) 
  14.  14     { 
  15.  15         perror("fail to pthread_create"); 
  16.  16         exit(-1); 
  17.  17     } 
  18.  18     while ( 1 ) 
  19.  19     { 
  20.  20         count++; 
  21.  21         value1 = count
  22.  22         value2 = count
  23.  23     } 
  24.  24     return 0; 
  25.  25 } 
  26.  26  
  27.  27 void  *function(void *arg) 
  28.  28 { 
  29.  29     while ( 1 ) 
  30.  30     { 
  31.  31         if (value1 != value2) 
  32.  32         {                                                                                                                                                                                          
  33.  33             printf("count=%d , value1=%d, value2=%d\n",  count, value1, value2); 
  34.  34             usleep(100000); 
  35.  35         }      
  36.  36     } 
  37.  37     return  NULL
  38.  38 }   

乍一看,該程序應該可以滿足我們的需要,并且程序運行的時候不應該打印任何內容,但是實際運行結果出乎我們意料。

編譯運行:

  1. gcc test.c -o run -lpthread 
  2. ./run 

代碼1執行結果

執行結果:

可以看到子程序會隨機打印一些信息,為什么還有這個執行結果呢?其實原因很簡單,就是我們文章開頭所說的,線程調度具有䘺隨機性,我們無法規定讓內核何時調度某個線程。有打印信息,那么這說明此時value1和value2的值是不同的,那也說明了調度子線程的時候,是在主線程向value1和value2之間的位置調度的。

 

代碼1執行的實際時序

實際上代碼的執行時序如下所示:

 

如上圖,在某一時刻,當程序走到**value2 = count;**這個位置的時候,內核對線程進行了調度,于是子進程在判斷value1和value2的值的時候,發現這兩個變量值不相同,就有了打印信息。

該程序在下面這兩行代碼之間調度的幾率還是很大的。

  1. value1 = count;  
  2. value2 = count

解決方法

如何來解決并發導致的程序沒有按預期執行的問題呢?對于線程來說,常用的方法有posix信號量、互斥鎖,條件變量等,下面我們以互斥鎖為例,講解如何避免代碼1的問題的出現。

互斥鎖的定義和初始化:

  1. pthread_mutex_t  mutex; 
  2. pthread_mutex_init(&mutex, NULL

申請釋放鎖:

  1. pthread_mutex_lock(&mutex); 
  2. pthread_mutex_unlock(&mutex); 

原理:進入臨界區之前先申請鎖,如果能獲得鎖就繼續往下執行, 如果申請不到,就休眠,直到其他線程釋放該鎖為止。

代碼2

  1. 1 #include <stdio.h> 
  2.  2 #include <stdlib.h> 
  3.  3 #include <string.h> 
  4.  4 #include <pthread.h> 
  5.  5 #include <unistd.h> 
  6.  6 #define _LOCK_ 
  7.  7 unsigned int value1,value2, count=0; 
  8.  8 pthread_mutex_t  mutex; 
  9.  9 void *function(void *arg); 
  10. 10  
  11. 11 int main(int argc,  char *argv[]) 
  12. 12 { 
  13. 13     pthread_t  a_thread; 
  14. 14           
  15. 15     if (pthread_mutex_init(&mutex, NULL) < 0)                                                                                                                                                           
  16. 16     { 
  17. 17         perror("fail to mutex_init"); 
  18. 18         exit(-1); 
  19. 19     } 
  20. 20  
  21. 21     if (pthread_create(&a_thread, NULLfunctionNULL) < 0) 
  22. 22     { 
  23. 23         perror("fail to pthread_create"); 
  24. 24         exit(-1); 
  25. 25     } 
  26. 26     while ( 1 ) 
  27. 27     { 
  28. 28         count++; 
  29. 29 #ifdef  _LOCK_ 
  30. 30         pthread_mutex_lock(&mutex); 
  31. 31 #endif 
  32. 32         value1 = count
  33. 33         value2 = count
  34. 34 #ifdef  _LOCK_ 
  35. 35         pthread_mutex_unlock(&mutex); 
  36. 36 #endif 
  37. 37     } 
  38. 38     return 0; 
  39. 39  } 
  40. 0  
  41. 41 void  *function(void *arg) 
  42. 42 { 
  43. 43      while ( 1 ) 
  44. 44      { 
  45. 45 #ifdef _LOCK_ 
  46. 46         pthread_mutex_lock(&mutex); 
  47. 47 #endif            
  48. 48  
  49. 49         if (value1 != value2)   
  50. 50         { 
  51. 51             printf("count=%d , value1=%d, value2=%d\n",  count, value1, value2); 
  52. 52             usleep(100000); 
  53. 53         }      
  54. 54 #ifdef _LOCK_ 
  55. 55         pthread_mutex_unlock(&mutex); 
  56. 56 #endif 
  57. 57      } 
  58. 58      return  NULL
  59. 59  }      

如上述代碼所示:主線程和子線程要訪問臨界資源value1,value2時,都必須先申請鎖,獲得鎖之后才可以訪問臨界資源,訪問完畢再釋放互斥鎖。該代碼執行之后就不會打印任何信息。我們來看下,如果程序在下述代碼之間產生調度時,程序的時序圖。

  1. value1 = count;  
  2. value2 = count

時序圖如下:

 


如上圖所示:

 

 

  1. 時刻n,主線程獲得mutex,從而進入臨界區;
  2. 時刻n+1,時間片到了,切換到子線程;
  3. n+2時刻子線程申請不到鎖mutex,所以放棄cpu,進入休眠;
  4. n+3時刻,主線程釋放mutex,離開臨界區,并喚醒阻塞在mutex的子線程,子線程申請到mutex,進入臨界區;
  5. n+4時刻,子線程離開臨界區,釋放mutex。

可以看到,加鎖之后,即使主線程在value2 =count; 之前產生了調度,子線程由于獲取不到mutex,會進入休眠,只有主線程出了臨界區,子線程才能獲得mutex,訪問value1和value2,就永遠不會打印信息,就實現了我們預期的代碼時序。

總結

實際項目中,可能程序的并發的情況可能會更加復雜,比如多個cpu上運行的任務之間,cpu運行的任務和中斷之間,中斷和中斷之間,都有可能并發。

有些調度的概率雖然很小,但是不代表不發生,而且由于資源同步互斥導致的問題,很難復現,縱觀Linux內核代碼,所有的臨界資源都會對應鎖。

多閱讀Linux內核源碼,學向大神學習,與大神神交。

正所謂代碼讀百遍,其義自見!熟讀代碼千萬行,不會編寫也會抄!

關于內核和應用程序的同步互斥的知識點,可以查看一口君的其他文章。

本文轉載自微信公眾號「一口Linux」,可以通過以下二維碼關注。轉載本文請聯系一口Linux公眾號。

 

責任編輯:武曉燕 來源: 一口Linux
相關推薦

2016-01-21 09:55:51

2013-04-25 09:55:21

進程線程

2024-12-03 00:44:50

2019-09-18 15:09:50

進程線程操作系統

2021-12-27 09:31:20

HashtableJava隨機數

2009-07-14 16:02:42

JDBC例子

2023-10-26 21:44:02

Java多線程方法

2022-09-08 06:23:37

C++HTTP 服務器

2013-06-08 13:07:23

Java線程池調度器

2022-10-31 07:09:15

拷貝代碼項目

2023-12-13 10:46:27

2020-03-26 17:00:53

HashMapputJava

2010-04-19 17:21:36

Oracle寫文件

2017-12-07 15:05:50

全球互聯網創新峰會

2020-04-03 09:45:09

Java多線程接口

2024-10-14 16:25:59

C#線程鎖代碼

2024-11-14 00:08:14

C#技術

2010-03-24 10:32:05

Python多線程

2024-11-15 11:00:00

C#多線程

2009-08-31 14:45:15

C#.NET多線程應用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲国产成人av好男人在线观看 | 日韩二区 | 69xxx免费| 久草网址 | 亚洲伊人久久综合 | 精品在线 | 欧美激情一区二区三区 | 欧美啊v在线观看 | 亚洲最大的成人网 | 玖玖在线精品 | 男女羞羞视频免费看 | 亚洲美女天堂网 | 毛片久久久 | 91久久精| 欧美一级片在线观看 | 久久久区 | 欧美色视频免费 | 亚洲狠狠丁香婷婷综合久久久 | 国产在线区 | 国产伦精品一区二区三区在线 | 亚洲国产成人精 | 欧美精品久久久久久 | 久久久国产精品一区 | 99reav| 少妇黄色 | 欧美日韩黄色一级片 | 福利视频日韩 | 精品视频在线免费观看 | 国产亚洲黄色片 | 中文字幕成人 | 国产日韩电影 | 午夜影院在线观看免费 | av中文字幕在线观看 | 91精品久久久久久久久 | 久久国产视频播放 | 免费成人毛片 | 亚洲欧美一区二区三区1000 | 91电影在线 | 91久久精品日日躁夜夜躁国产 | 亚洲一区久久久 | 成人影音|