Posix線程 它們那一大家子事兒,要覺得好你就收藏進被窩里慢慢看 (1)

      網友投稿 751 2025-04-01

      文章目錄

      ①大神博客先推

      ②好,現在看我的

      線程是啥玩意兒? 非要線程不可?

      線程與進程千絲萬縷的糾纏

      線程間資源共享情況

      ⑴共享資源

      ⑵非共享資源

      線程的缺點

      ③線程安全問題

      這個模塊他的博客里沒

      ④嗶嗶完了不?放碼過來!

      創建線程

      接下來演示線程安全:

      獲取當前線程id

      判斷倆線程是否相等

      單次初始化

      連接(Joining)和分離(Detaching)線程

      又到了演示線程安全的時間了

      ⑤線程屬性

      ⑥敲黑板:棧管理

      準備好小板凳

      未完待續···

      ①大神博客先推

      我這人就是這么的無私,這位大神應該是退隱好幾年了,但是留下了不少好東西。

      Posix線程詳解

      不過我的小白文也有不少彩蛋哦↓↓↓

      ②好,現在看我的

      畢竟大神的博客也太長了,而且深奧,大家就好了。

      咱這個短,通俗易懂。

      線程是啥玩意兒? 非要線程不可?

      官方話就是:是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發多個線程,每條線程并行執行不同的任務。

      1、提高程序的并發性 2、開銷小,不需要重新分配內存 3、通信和共享數據方便

      1

      2

      3

      還真別說,大神就是厲害,這還有圖有真相!!!

      線程與進程千絲萬縷的糾纏

      (1)線程又被叫做輕量級進程,也有PCB,創建線程使用的底層函數和進程是一樣的,都是clone。 (2)從內核里看線程和進程是一樣的,都有各自不同的PCB,但是PCB指向的內存資源的三級頁表是不同的。 (3)進程可以蛻變成線程,進程也可以說是主線程,就是高速路的主干道。 (4)在Linux下,線程是最小的執行單位,進程是最小的分配資源單位。

      1

      2

      3

      4

      線程間資源共享情況

      1、文件描述符表

      2、每種信號的處理方式

      3、當前工作目錄

      4、用戶ID和組ID

      5、內存地址空間

      1、線程id

      2、處理器現場和棧指針

      3、獨立的棧空間

      4、errno變量

      5、信號屏蔽字

      6、調度優先級

      線程的缺點

      1、線程不穩定(這個是真的不穩定,后面章節會提) 2、線程調試困難(這個是真的頭疼,難以調試的東西) 3、線程無法使用Unix經典事件,如信號

      1

      2

      3

      ③線程安全問題

      線程安全(Thread-safeness):

      線程安全:簡短的說,指程序可以同時執行多個線程卻不會“破壞“共享數據或者產生“競爭”條件的能力。

      例如:假設你的程序創建了幾個線程,每一個調用相同的庫函數:

      這個庫函數存取/修改了一個全局結構或內存中的位置。

      當每個線程調用這個函數時,可能同時去修改這個全局結構活內存位置。

      如果函數沒有使用同步機制去阻止數據破壞,這時,就不是線程安全的了。

      這個模塊他的博客里沒

      嘿嘿,如果看我的博客,那這就是一個彩蛋了。

      我有???可重入函數對于線程安全的意義(附函數表)

      ④嗶嗶完了不?放碼過來!

      創建線程

      pthread_create

      1

      功能:創建一個線程

      原語函數:

      #include int pthread_create(pthread_t *thread,const pthread_tattr_t *attr,void *(*start_routine)(void *),void *arg);

      1

      2

      3

      參數釋義:

      thread:傳遞一個pthread_t變量進來,用以保存新線程的tid(線程id)

      attr:線程屬性設置,NULL代表使用默認屬性(注(1))

      (*start_routine)(void *):函數指針,指向新線程應該指向的函數模塊

      arg:老熟了,給前面那個函數傳參用的,不傳就寫NULL

      返回值:成功返回0.,失敗返回錯誤號,錯誤號,錯誤號,前面說過errno不共享的。(線程里返回值統一這樣的,后面不提了)

      注(1):創建線程時,沒什么特殊情況我們都是使用默認屬性的,不過有時候需要做一些特殊處理,碧如調整優先級啊這些的。后面會說。

      Q:怎樣安全地向一個新創建的線程傳遞數據?

      A:確保所傳遞的數據是線程安全的(不能被其他線程修改)。下面三個例子演示了那個應該和那個不應該。

      我的代碼太菜了,看那個大神的:

      Example Code - Pthread Creation and Termination #include #include #define NUM_THREADS 5 void *PrintHello(void *threadid) { int tid; tid = (int)threadid; printf("Hello World! It's me, thread #%d!\n", tid); pthread_exit(NULL); } int main (int argc, char *argv[]) { pthread_t threads[NUM_THREADS]; int rc, t; for(t=0; t

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      //下面的代碼片段演示了如何向一個線程傳遞一個簡單的整數。 //主線程為每一個線程使用一個唯一的數據結構,確保每個線程傳遞的參數是完整的。 int *taskids[NUM_THREADS]; for(t=0; t

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      //例子展示了用結構體向線程設置/傳遞參數。每個線程獲得一個唯一的結構體實例。 struct thread_data{ int thread_id; int sum; char *message; }; struct thread_data thread_data_array[NUM_THREADS]; void *PrintHello(void *threadarg) { struct thread_data *my_data; ... my_data = (struct thread_data *) threadarg; taskid = my_data->thread_id; sum = my_data->sum; hello_msg = my_data->message; ... } int main (int argc, char *argv[]) { ... thread_data_array[t].thread_id = t; thread_data_array[t].sum = sum; thread_data_array[t].message = messages[t]; rc = pthread_create(&threads[t], NULL, PrintHello, (void *) &thread_data_array[t]); ... }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      //例子演示了錯誤地傳遞參數。循環會在線程訪問傳遞的參數前改變傳遞給線程的地址的內容。 int rc, t; for(t=0; t

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      獲取當前線程id

      pthread_self

      1

      功能:獲取調用線程tid(注(3))

      注(3):有的人就要問了,這東西不是都傳出來了嗎,直接打印不就完事兒了嗎,為什么還要特地開一個函數去獲取?

      是這樣的,線程id的類型是pthread_t,它在當前進程中是唯一的,但是在不同系統中這個類型有不同的實現,它可能是一個整數值,也可能是一個結構體,反正就是你猜不到的東西。

      好,看原語:

      #include pthread_t pthread_self(void);

      1

      2

      3

      判斷倆線程是否相等

      pthread_equal

      1

      功能:判斷兩個線程是否相等

      原語:

      #include int pthread_self(pthread_t t1,pthread_t t2);

      1

      2

      3

      注意這兩個函數中的線程ID對象是不透明的,不是輕易能檢查的。因為線程ID是不透明的對象,所以C語言的==操作符不能用于比較兩個線程ID。

      單次初始化

      pthread_once (once_control, init_routine) pthread_once 在一個進程中僅執行一次init_routine。 任何線程第一次調用該函數會執行給定的init_routine,不帶參數,任何后續調用都沒有效果。 init_routine函數一般是初始化的程序 once_control參數是一個同步結構體,需要在調用pthread_once前初始化。

      1

      2

      3

      4

      5

      6

      例如:

      pthread_once_t once_control = PTHREAD_ONCE_INIT;

      1

      連接(Joining)和分離(Detaching)線程

      Posix線程 它們那一大家子事兒,要覺得好你就收藏進被窩里慢慢看 (1)

      pthread_join(threadid,status) pthread_detach(threadid,status) pthread_attr_setdetachstate(attr,detachstate) pthread_attr_getdetachstate(attr,detachstate)

      1

      2

      3

      4

      5

      6

      7

      連接:

      “連接”是一種在線程間完成同步的方法。例如:

      > pthread_join()函數阻賽調用線程直到threadid所指定的線程終止。 > 如果在目標線程中調用pthread_exit(),程序員可以在主線程中獲得目標線程的終止狀態。 > > 連接線程只能用pthread_join()連接一次。若多次調用就會發生邏輯錯誤。 > > 兩種同步方法,互斥量(mutexes)和條件變量(condition variables),稍后討論。

      1

      2

      3

      4

      5

      6

      可連接(Joinable or Not)?

      當一個線程被創建,它有一個屬性定義了它是可連接的(joinable)還是分離的(detached)。 只有是可連接的線程才能被連接(joined),若果創建的線程是分離的,則不能連接。 POSIX標準的最終草案指定了線程必須創建成可連接的。然而,并非所有實現都遵循此約定。 使用pthread_create()的attr參數可以顯式的創建可連接或分離的線程

      1

      2

      3

      4

      5

      6

      7

      典型四步如下:

      聲明一個pthread_attr_t數據類型的線程屬性變量 用 pthread_attr_init()初始化改屬性變量 用pthread_attr_setdetachstate()設置可分離狀態屬性 完了后,用pthread_attr_destroy()釋放屬性所占用的庫資源

      1

      2

      3

      4

      5

      6

      7

      分離(Detaching):

      pthread_detach()可以顯式用于分離線程,盡管創建時是可連接的。

      沒有與pthread_detach()功能相反的函數

      建議:

      若線程需要連接,考慮創建時顯式設置為可連接的。因為并非所有創建線程的實現都是將線程創建為可連接的。

      若事先知道線程從不需要連接,考慮創建線程時將其設置為可分離狀態。一些系統資源可能需要釋放。

      //這個例子演示了用Pthread join函數去等待線程終止。 //因為有些實現并不是默認創建線程是可連接狀態,例子中顯式地將其創建為可連接的。 #include #include #define NUM_THREADS 3 void *BusyWork(void *null) { int i; double result=0.0; for (i=0; i<1000000; i++) { result = result + (double)random(); } printf("result = %e\n",result); pthread_exit((void *) 0); } int main (int argc, char *argv[]) { pthread_t thread[NUM_THREADS]; pthread_attr_t attr; int rc, t; void *status; /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for(t=0; t

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      ⑤線程屬性

      linux下線程屬性是可以根據實際項目需要進行設置。

      之前我們討論的都是線程的默認屬性,默認屬性已經可以解決大部分線程開發時的需求。

      如果需要更高的性能,就需要人為對線程屬性進行配置。

      typedef struct { int detachstate; //線程的分離狀態 int schedpolicy; //線程的調度策略 struct sched schedparam;//線程的調度參數 int inheritsched; //線程的繼承性 int scope; //線程的作用域 size_t guardsize; //線程棧末尾的警戒緩沖區大小 int stackaddr_set; //線程棧的設置 void* stackaddr; //線程棧的啟始位置 size_t stacksize; //線程棧大小 }pthread_attr_t; //在上面我們可以看到,關于這個結構體中的相關參數

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      默認的屬性為非綁定、非分離、缺省的堆棧、與父進程同樣級別的優先級。

      線程屬性設置的一般套路:

      第一:定義屬性變量并初始化 pthread_attr_t pthread_attr_init() 第二:調用你想設置的屬性的接口函數 pthread_attr_setxxxxxxxx() 第三:創建線程的時候,第二個參數使用這個屬性 第四:銷毀屬性 pthread_destroy();

      1

      2

      3

      4

      5

      6

      7

      8

      ⑥敲黑板:棧管理

      防止棧問題:

      POSIX標準并沒有指定線程棧的大小,依賴于實現并隨實現變化。

      很容易超出默認的棧大小,常見結果:程序終止或者數據損壞。

      安全和可移植的程序應該不依賴于默認的棧限制,但是取而代之的是用pthread_attr_setstacksize分配足夠的棧大小。

      pthread_attr_getstackaddr和pthread_attr_setstackaddr函數可以被程序用于將棧設置在指定的內存區域。

      pthread_attr_getstacksize (attr, stacksize) pthread_attr_setstacksize (attr, stacksize) pthread_attr_getstackaddr (attr, stackaddr) pthread_attr_setstackaddr (attr, stackaddr)

      1

      2

      3

      4

      5

      6

      7

      //這個例子演示了如何去查詢和設定線程棧大小。 #include #include #define NTHREADS 4 #define N 1000 #define MEGEXTRA 1000000 pthread_attr_t attr; void *dowork(void *threadid) { double A[N][N]; int i,j,tid; size_t mystacksize; tid = (int)threadid; pthread_attr_getstacksize (&attr, &mystacksize); printf("Thread %d: stack size = %li bytes /n", tid, mystacksize); for (i=0; i

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      未完待續···

      想了想,線程同步模塊和線程池放在下一個章節吧,我沒有文章字數破W的好習慣??

      任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Excel表格自動排序的方法
      下一篇:Python Collections模塊
      相關文章
      久久亚洲成a人片| 亚洲日本精品一区二区| 亚洲日韩在线观看免费视频| 亚洲永久在线观看| 亚洲精品成人网站在线观看| 亚洲午夜福利精品无码| 亚洲第一综合天堂另类专| 四虎必出精品亚洲高清| 亚洲精品天堂在线观看| 亚洲国产成a人v在线| 4444亚洲国产成人精品| 亚洲AV天天做在线观看| 亚洲AV乱码一区二区三区林ゆな| 亚洲中文字幕不卡无码| 国产精品亚洲一区二区三区在线| 国产亚洲人成网站观看| 亚洲国产成人一区二区三区| 亚洲好看的理论片电影| 亚洲系列中文字幕| 亚洲一级黄色大片| 亚洲人成无码网站在线观看| 老司机亚洲精品影院在线观看 | 无码色偷偷亚洲国内自拍| 久久久久亚洲精品无码网址色欲| 国产精品亚洲天堂| 亚洲日韩在线第一页| 亚洲码国产精品高潮在线| 亚洲国产成人久久综合碰碰动漫3d | 亚洲国产综合精品中文第一| 亚洲色大成网站www尤物| 婷婷国产偷v国产偷v亚洲| 亚洲中文字幕伊人久久无码| 亚洲人成色777777在线观看| 亚洲中文字幕在线观看| 久久精品亚洲日本佐佐木明希| 亚洲综合久久1区2区3区| 久久久久精品国产亚洲AV无码| 亚洲精品国产精品| 亚洲男人天堂2020| 久久久亚洲精品视频| 亚洲午夜精品一区二区公牛电影院 |