日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux多线程编写哲学家,Linux系统编程(三) ------ 多线程编程

發布時間:2025/3/21 linux 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux多线程编写哲学家,Linux系统编程(三) ------ 多线程编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、線程的創建和調度

1.線程是程序執行的某一條指令流的映像。

為了進一步減少處理機制的空轉時間,支持多處理器及減少上下文切換開銷,進程在演化中出現了另一個概念——線程。它是進程內獨立的一條運行路線,是處理器調用的最小單元,也可以成為輕量級進程。

進程標識符在內部唯一,只為了進程內的區分。

線程可以對進程的內存空間和資源進程訪問,并與同一個進程中的其他線程共享。因此,雖然每個線程同樣得開辟一定大小空間擁有自己的棧空間,擁有獨立的執行序列,但線程上下文切換的開銷比創建進程小得多。

在串行程序基礎上引入線程和進程是為了提高程序的并發度,從而提高程序運行效率和響應時間。

線程和進程在使用上各有優缺點:

線程執行開銷小,但不利于資源的管理和保護;而進程正相反。同時,線程適合于在SMP機器上運行,而進程則可以跨機器遷移。

2.線程函數,用于提供線程執行的指令(代碼)。

向線程函數傳遞參數分為兩種:

1)線程函數只有一個參數的情況:直接定義一個變量通過應用傳給線程函數。

2)線程函數有多個參數的情況:此時就必須申明一個結構體來包含所有的參數,然后在傳入線程函數。

3.線程庫

#include ```

Linux系統下的多線程遵循POSIX線程接口,稱為pthread。

pthread_t 在頭文件/usr/include/bits/pthreadtypes.h中定義:

typedef unsigned long int pthread_t;

它是一個線程的標識符。在編譯命令末注意加上-lpthread參數,以調用靜態鏈接庫。因為pthread并非Linux系統的默認庫。

####4.使用pthread_create()函數創建線程:

>函數原型

```c

int pthread_create(pthread_t *tid, const pthread_attr_t *tattr, void *(*start_routine)(void *), void *arg);```

*函數參數及說明:*

- 第一個參數為指向線程標識符的指針。返回成功時,由tid指向的內存單元被設置為新創建線程的線程ID。

- 第二個參數用來設置各種不同的線程屬性。

- 第三個參數是線程運行函數的起始地址。新創建的線程從start_routine函數的地址開始運行,該函數只有一個萬能指針參數arg,如果需要向start_routine函數傳遞的參數不止一個,那么需要把這些參數放到一個結構中,然后把這個結構的地址作為arg的參數傳入。

- 最后一個參數是運行函數的參數。arg指針是最初唯一對指針所指向的對象進行存取的方法,僅當第二個指針基于第一個時,才能對對象進行存取。對對象的存取都限定于基于由arg指針表達式中。 由arg指針主要用于函數形參,或指向由 malloc() 分配的內存空間。arg 數據類型不改變程序的語義。編譯器能通過作出arg指針是存取對象的唯一方法的假設,更好地優化某些類型的進程。

*函數返回值:*函數成功返回0。任何其他返回值都表示錯誤。

####5.使用pthread_join()函數以阻塞的方式等待thread指定的線程結束。

```c

int pthread_join(pthread_t thread, void **retval);

函數參數及說明:

第一個參數為被等待的線程標識符,標識唯一線程。

第二個參數為一個用戶定義的指針,它可以用來存儲被等待線程的返回值。

這個函數是一個線程阻塞的函數,調用它的函數將一直等待到被等待的線程結束為止,當函數返回時,被等待線程的資源被收回。如果線程已經結束,那么該函數會立即返回。

如果沒有pthread_join()主線程會很快結束從而使整個進程結束,從而使創建的線程沒有機會開始執行就結束了。加入pthread_join()后,主線程會一直等待直到等待的線程結束自己才結束,使創建的線程有機會執行。

函數返回值:函數執行成功返回0。任何其他返回值都表示錯誤。

提示:

在多線程編程的時候我們往往都是以for循環的形式調用,實際上主線程在第1個線程處就掛起了,在等待1號線程結束后再等待2號線程。當然會出現3,4,5比1,2先結束的情況。主線程還是在等待1,2結束后,發現3,4,5其實早已經結束了,就會回收3,4,5的資源,然后主線程再退出。

6.使用pthread_exit()函數終止并線程

void pthread_exit(void *retval);```

*函數說明及返回值:*

是線程的主動行為;由于一個進程中的多個線程是共享數據段的,因此通常在線程退出之后,退出線程所占用的資源并不會隨著線程的終止而得到釋放,但是可以用pthread_join()函數來配合同步并釋放資源。pthread_exit()終止調用它的線程并返回一個指向某個對象的指針,該返回值可以通過pthread_join函數的第二個參數得到。

唯一的參數是函數的返回代碼,只要pthread_join中的第二個參數不是NULL,這個值將被傳遞給retval。要說明的是,一個線程不能被多個線程等待,否則第一個接收到信號的線程成功返回,其余調用pthread_join的線程則返回錯誤代碼。

####7.使用pthread_self()函數獲取當前線程的標識符:

```c

pthread_t pthread_self(void);```

返回獲得當前線程自身的標示符ID。pthread_t的類型為unsigned long int,所以在打印的時候要使用%ld方式,否則將產生奇怪的結果。

####8.使用pthread_equal()函數比較判斷是否是同一個線程:

```c

int pthread_equal(pthread_t tid1, pthread_t tid2);```

如果tid1和tid2相同,函數返回一個非0值,否則返回0。

如果tid1或tid2中任何一個是非法值,則返回將是不可預料的。

####9.使用pthread_cancel()取消指定線程:

```c

int pthread_cancel(pthread_t thread);```

*函數返回值:*函數成功返回0。任何其他返回值都表示錯誤。

退出一個線程。

如何響應退出請求取決于目標線程的狀態。

當然,線程也不是被動的被別人結束。它可以通過設置自身的屬性來決定如何結束。

線程的被動結束分為兩種,一種是異步終結,另外一種是同步終結。異步終結就是當其他線程調用 pthread_cancel的時候,線程就立刻被結束。而同步終結則不會立刻終結,它會繼續運行,直到到達下一個結束點(cancellation point)。當一個線程被按照默認的創建方式創建,那么它的屬性是同步終結。

發送終止信號給thread線程,如果成功則返回0,否則為非0值。發送成功并不意味著thread會終止。

##二、線程并發要求

1.同步,代碼依賴資源有前后關系(競爭),試衣間(互斥)。進程/線程中的部分指令需要按照一定 順序前后執行。

2.競爭,有競爭才會同步。對于有限資源的共享使用過程中產生的競爭關系。

3.互斥,對于共享資源的操作同時只能有一個進程/線程。

4.死鎖,互相等待資源。//不應有

5.饑餓,長時間(設置時間點)無法獲取資源。//不應有

6.異步,完全沒有關系。不用去保護。進程/線程之間的指令執行無順序。

[并發性:互斥和同步、死鎖和饑餓 ](http://blog.csdn.net/u013271921/article/details/45459351)

[進程同步互斥——不死鎖的哲學家問題](http://www.oschina.net/code/snippet_180916_7504)

[操作系統中的互斥,同步與死鎖 ](http://blog.csdn.net/t_tbread/article/details/22678549)

##三、線程間通信

信息數據交換,使用多個線程都可見的內存區域。A產生的B使用。標識符

###保護機制:

#####1.線程互斥鎖:

**互斥量(Mutex)**是“mutual exclusion”的縮寫。互斥量是實現線程同步,和保護同時寫共享數據的主要方法。保障有同一把鎖保護的共享資源被多個線程互斥訪問。互斥量對共享數據的保護就像一把鎖。

######互斥量必須用類型pthread_mutex_t類型聲明。

對臨界區加鎖以實現互斥,當某個進程進入臨界區之后,它將鎖上臨界區,直到它退出臨界區為止。

>互斥鎖初始化函數

```c

int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);```

***函數說明:***

該函數用于C函數的多線程編程中,互斥鎖的初始化。

***函數參數:***

函數是以動態方式創建互斥鎖的,第一個參數 mutex 是指向要初始化的互斥鎖的指針。第二個參數 attr 是指向新建互斥鎖屬性對象的指針,該屬性對象定義要初始化的互斥鎖的屬性。如果該指針為 NULL,則使用默認的快速互斥鎖屬性。

互斥鎖的屬性在創建鎖的時候指定,在LinuxThreads實現中僅有一個鎖類型屬性,不同的鎖類型在試圖對一個已經被鎖定的互斥鎖加鎖時表現不同。

***函數返回值:***執行成功完成之后會返回0,其他任何返回值都表示出現了錯誤。

函數成功執行后,互斥鎖被初始化為鎖住態。

[線程同步:互斥量,死鎖](http://blog.csdn.net/tototuzuoquan/article/details/39553761)

>互斥鎖的獲取(加鎖)

```c

int pthread_mutex_lock(pthread_mutex_t *mutex);```

互斥鎖的釋放(解鎖)

```c

int pthread_mutex_unlock(pthread_mutex_t *mutex);```

以上兩個不可能被兩個不同的線程同時得到,而必須等待解鎖。

在同一進程中的線程,如果加鎖后沒有解鎖,則任何其他線程都無法再獲得鎖。

pthread_mutex_lock()聲明開始用互斥鎖上鎖,此后的代碼直至調用pthread_mutex_unlock()為止,均被上鎖,即同一時間只能被一個線程調用執行。當一個線程執行到pthread_mutex_lock()處時,如果該鎖此時被另一個線程使用,那此線程被阻塞,即程序將等待到另一個線程釋放此互斥鎖。

多個線程對資源改寫都要互斥(保護)

***提示:***總體來講, 有幾個不成文的基本原則:

- 對共享資源操作前一定要獲得鎖。

- 完成操作以后一定要釋放鎖。

- 盡量短時間地占用鎖。

- 如果有多鎖, 如獲得順序是ABC連環扣, 釋放順序也應該是ABC。

- 線程錯誤返回時應該釋放它所獲得的鎖。

[pthreads線程(二) 線程同步--互斥量/鎖](http://www.cnblogs.com/dongsheng/p/4186358.html)

####2.線程信號量:解決多個線程在使用共享有限資源的同步問題。

線程的信號量與進程間通信中使用的信號量的概念是一樣,它是一種特殊的變量,它可以被增加或減少,但對其的關鍵訪問被保證是原子操作。如果一個程序中有多個線程試圖改變一個信號量的值,系統將保證所有的操作都將依次進行。

而只有0和1兩種取值的信號量叫做二進制信號量,在這里將重點介紹。而信號量一般常用于保護一段代碼,使其每次只被一個執行線程運行。我們可以使用二進制信號量來完成這個工作。

信號量是一個計數器,用于控制訪問有限共享資源的線程數。

在操作系統中,信號量是一整數,在sem大于等于零時代表可供并發進程使用的資源實體數,但sem小于零時表示正在等待使用臨界區的進程數;

線程信號量,sem_t

>信號量的創建和初始化:

```c

#include

int sem_init (sem_t *sem, int pshared, unsigned int value);```

該函數初始化由sem指向的信號對象,設置它的共享選項,并給它一個初始的整數值。pshared控制信號量的類型,如果其值為0,就表示這個信號量是當前進程的局部信號量,否則信號量就可以在多個進程之間共享,value為sem的初始值。調用成功時返回0,失敗返回-1。

>信號量的獲取,以原子操作的方式將信號量的值--1。

```c

int sem_wait(sem_t * sem);```

sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1。

>信號量的釋放,以原子操作的方式將信號量的值++1。

```c

int sem_post(sem_t * sem);```

與sem_wait一樣,sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1。

>信號量的銷毀,用于對用完的信號量的清理。

```c

int sem_destroy (sem_t *sem);```

成功時返回0,失敗時返回-1。

[Linux多線程——使用信號量同步線程 ](http://blog.csdn.net/ljianhui/article/details/10813469/)

[線程同步(互斥鎖與信號量的作用與區別)](http://blog.csdn.net/tietao/article/details/7367827)

####3.原子操作

暨如果兩個線程企圖同時給一個信號量++1或--1,它們之間不會互相干擾。是最安全的操作,用鎖鎖在一起,或全執行,或全擱置。

#####課程使用各參數(暫時)安排

創建線程:

#include

//全局變量,可以是結構體,整型變量,等等。

void *thread_func(void *arg);//聲明線程函數

//主調函數內:

pthread_t thread_id; //注冊定義線程id

pthread_create(&thread_id, NULL, thread_func, NULL); //創建線程并指定線程的執行函數,最后一個參數為傳到線程函數的參數。

pthread_join(thread_id, NULL); // 等待指定線程的退出

//自定義線程函數內:

pthread_exit(NULL);//返回到join后一個參數。

線程互斥鎖:

pthread_mutex_t mutex;//全局定義線程互斥鎖

主調函數內:

注冊定義線程id

pthread_mutex_init(&mutex, NULL);//初始化線程互斥鎖

創建線程

等待線程退出

自定義線程函數內:

pthread_mutex_lock(&mutex);// 獲取互斥鎖

pthread_mutex_unlock(&mutex); // 釋放互斥鎖

!!互斥鎖的獲取和釋放必須成對出現!!

信號量:

sem_t sem;//全局定義信號量

void sig_handler(int signo);//聲明信號處理函數

主調函數內:

注冊定義線程id

signal(SIGINT, sig_handler);//注冊信號處理函數

sem_init(&sem, 0, 0);// 初始化信號量為0

創建線程

等待線程退出

sem_destroy(&sem);// 銷毀信號量

自定義線程函數內:

while(1)

sem_wait(&sem);// sem -1 對信號量進行wait(即-1)操作,如果<0,阻塞。

自定義信號處理函數內:

sem_post(&sem);//sem +1 對信號量進行post(即+1)操作,如果<=0,系統喚醒一個等待線程。

[進程同步互斥——不死鎖的哲學家問題](http://www.oschina.net/code/snippet_180916_7504)

[競爭與同步,互斥量,信號量,死鎖,條件變量,哲學家吃飯問題](http://www.th7.cn/system/lin/201509/134476.shtml)

####參考資料

[對Linux中多線程編程中pthread_join的理解](http://www.linuxidc.com/Linux/2013-09/89931.htm)

[Linux 線程操作函數技能總結](http://blog.csdn.net/shaderdx/article/details/50475982)

[pthread多線程編程的學習小結](https://www.oschina.net/question/234345_40365)

[pThreads線程(一) 基本API](http://www.cnblogs.com/dongsheng/p/4184153.html)

[Linux Pthread 深入解析](http://blog.csdn.net/u010009623/article/details/53116814)

總結

以上是生活随笔為你收集整理的linux多线程编写哲学家,Linux系统编程(三) ------ 多线程编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。