一、Linux線程互斥
1.進(jìn)程線程間的互斥相關(guān)背景概念
臨界資源:多線程執(zhí)行流共享的資源就叫做臨界資源
臨界區(qū):每個線程內(nèi)部,訪問臨界資源的代碼,就叫做臨界區(qū)
互斥:任何時刻,互斥保證有且只有一個執(zhí)行流進(jìn)入臨界區(qū),訪問臨界資源,通常對臨界資源起保護(hù)作用
原子性:不會被任何調(diào)度機(jī)制打斷的操作,該操作只有兩態(tài),要么完成,要么未完成
大部分情況,線程使用的數(shù)據(jù)都是局部變量,變量的地址空間在線程??臻g內(nèi),這種情況,變量歸屬單個線程,其他線程無法獲得這種變量。
但有時候,很多變量都需要在線程間共享,這樣的變量稱為共享變量,可以通過數(shù)據(jù)的共享,完成線程之間的交互。
多個線程并發(fā)的操作共享變量,會帶來一些問題。
我們來看下面搶票的代碼:
#include <iostream>
#include <vector>
#include <unistd.h>
#include <pthread.h>
int tickets = 10000;
void *getTicket(void *args)
{
std::string threadname = static_cast<const char *>(args);
while (true)
{
if (tickets > 0)
{
usleep(1000);
std::cout << threadname << " 正在進(jìn)行搶票: " << tickets << std::endl;
tickets--;
}
else
{
break;
}
}
return nullptr;
}
int main()
{
pthread_t t1, t2, t3, t4;
pthread_create(&t1, nullptr, getTicket, (void *)"thread 1");
pthread_create(&t2, nullptr, getTicket, (void *)"thread 2");
pthread_create(&t3, nullptr, getTicket, (void *)"thread 3");
pthread_create(&t4, nullptr, getTicket, (void *)"thread 4");
pthread_join(t1, nullptr);
pthread_join(t2, nullptr);
pthread_join(t3, nullptr);
pthread_join(t4, nullptr);
return 0;
}
我們發(fā)現(xiàn)最終票的數(shù)量是負(fù)數(shù),這顯然是不合理的
為什么可能無法獲得爭取結(jié)果?
if 語句判斷條件為真以后,代碼可以并發(fā)的切換到其他線程
usleep 這個模擬漫長業(yè)務(wù)的過程,在這個漫長的業(yè)務(wù)過程中,可能有很多個線程會進(jìn)入該代碼段
–ticket 操作本身就不是一個原子操作
取出ticket--部分的匯編代碼
objdump -d a.out > test.objdump
152 40064b: 8b 05 e3 04 20 00 mov 0x2004e3(%rip),%eax # 600b34 <ticket>
153 400651: 83 e8 01 sub $0x1,%eax
154 400654: 89 05 da 04 20 00 mov %eax,0x2004da(%rip) # 600b34 <ticket>
– 操作并不是原子操作,而是對應(yīng)三條匯編指令:
load :將共享變量ticket從內(nèi)存加載到寄存器中
update : 更新寄存器里面的值,執(zhí)行-1操作
store :將新值,從寄存器寫回共享變量ticket的內(nèi)存地址
對變量進(jìn)行++,或者–,在C、C++上,看起來只有一條語句,但是匯編之后至少是三條語句:
1.從內(nèi)存讀取數(shù)據(jù)到CPU寄存器中
⒉.在寄存器中讓CPU進(jìn)行對應(yīng)的算邏運(yùn)算
3.寫回新的結(jié)果到內(nèi)存中變量的位置
要解決以上問題,需要做到三點(diǎn):
代碼必須要有互斥行為:當(dāng)代碼進(jìn)入臨界區(qū)執(zhí)行時,不允許其他線程進(jìn)入該臨界區(qū)。
如果多個線程同時要求執(zhí)行臨界區(qū)的代碼,并且臨界區(qū)沒有線程在執(zhí)行,那么只能允許一個線程進(jìn)入該臨界區(qū)。
如果線程不在臨界區(qū)中執(zhí)行,那么該線程不能阻止其他線程進(jìn)入臨界區(qū)。
要做到這三點(diǎn),本質(zhì)上就是需要一把鎖。Linux上提供的這把鎖叫互斥量。
我們定義的全局變量,在沒有保護(hù)的時候,往往是不安全的,像上面多個線程在交替執(zhí)行造成的數(shù)據(jù)安全問題,發(fā)生了數(shù)據(jù)不一致問題!
2.互斥量的接口
初始化互斥量
初始化互斥量有兩種方法:
方法1,靜態(tài)分配:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
方法2,動態(tài)分配:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrictattr);
參數(shù):
mutex:要初始化的互斥量
attr:NULL
銷毀互斥量
銷毀互斥量需要注意:
使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要銷毀
不要銷毀一個已經(jīng)加鎖的互斥量
已經(jīng)銷毀的互斥量,要確保后面不會有線程再嘗試加鎖
互斥量加鎖和解鎖
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失敗返回錯誤號
調(diào)用 pthread_ lock 時,可能會遇到以下情況:
互斥量處于未鎖狀態(tài),該函數(shù)會將互斥量鎖定,同時返回成功
發(fā)起函數(shù)調(diào)用時,其他線程已經(jīng)鎖定互斥量,或者存在其他線程同時申請互斥量,但沒有競爭到互斥量,那么pthread_ lock調(diào)用會陷入阻塞(執(zhí)行流被掛起),等待互斥量解鎖。
1.使用靜態(tài)分配的鎖–全局的鎖
#include <iostream>
#include <vector>
#include <unistd.h>
#include <pthread.h>
int tickets = 10000;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *getTicket(void *args)
{
std::string threadname = static_cast<const char *>(args);
while (true)
{
pthread_mutex_lock(&mutex);
if (tickets > 0)
{
usleep(1000);
std::cout << threadname << " 正在進(jìn)行搶票: " << tickets << std::endl;
tickets--;
pthread_mutex_unlock(&mutex);
}
else
{
pthread_mutex_unlock(&mutex);
break;
}
}
return nullptr;
}
int main()
{
pthread_t t1, t2, t3, t4;
pthread_create(&t1, nullptr, getTicket, (void *)"thread 1");
pthread_create(&t2, nullptr, getTicket, (void *)"thread 2");
pthread_create(&t3, nullptr, getTicket, (void *)"thread 3");
pthread_create(&t4, nullptr, getTicket, (void *)"thread 4");
pthread_join(t1, nullptr);
pthread_join(t2, nullptr);
pthread_join(t3, nullptr);
pthread_join(t4, nullptr);
return 0;
}
2.使用動態(tài)分配的鎖
#include <iostream>
#include <vector>
#include <unistd.h>
#include <pthread.h>
int tickets = 10000;
class threadData
{
public:
threadData(const std::string &threadname, pthread_mutex_t *mutex_p)
: _threadname(threadname), _mutex_p(mutex_p)
{
}
~threadData() {}
public:
std::string _threadname;
pthread_mutex_t *_mutex_p;
};
void *getTicket(void *args)
{
threadData *td = static_cast<threadData *>(args);
while (true)
{
pthread_mutex_lock(td->_mutex_p);
if (tickets > 0)
{
usleep(1000);
std::cout << td->_threadname << " 正在進(jìn)行搶票: " << tickets << std::endl;
tickets--;
pthread_mutex_unlock(td->_mutex_p);
}
else
{
pthread_mutex_unlock(td->_mutex_p);
break;
}
}
return nullptr;
}
int main()
{
#define NUM 4
pthread_mutex_t lock;
pthread_mutex_init(&lock, nullptr);
std::vector<pthread_t> tids(NUM);
for (int i = 0; i < NUM; i++)
{
char buffer[64];
snprintf(buffer, sizeof buffer, "thread %d", i + 1);
threadData *td = new threadData(buffer, &lock);
pthread_create(&tids[i], nullptr, getTicket, td);
}
for (int i = 0; i < NUM; i++)
{
pthread_join(tids[i], nullptr);
}
return 0;
}
我們發(fā)現(xiàn)在我們進(jìn)行加鎖之后,程序運(yùn)行變慢了,這是因?yàn)樵谂R界區(qū)中程序都是串行執(zhí)行的
加鎖和解鎖的過程多個線程串行執(zhí)行的,程序變慢了!
鎖只規(guī)定互斥訪問,沒有規(guī)定必須讓誰優(yōu)先執(zhí)行
鎖就是真是的讓多個執(zhí)行流進(jìn)行競爭的結(jié)果
- 如何看待鎖
a. 鎖,本身就是一個共享資源!全局的變量是要被保護(hù)的,鎖是用來保護(hù)全局的資源的,鎖本身也是全局資源,鎖的安全誰來保護(hù)呢?
b. pthread_mutex_lock、pthread_mutex_unlock:加鎖的過程必須是安全的!加鎖的過程其實(shí)是原子的!
c. 如果申請成功,就繼續(xù)向后執(zhí)行,如果申請暫時沒有成功,執(zhí)行流會阻塞!
d. 誰持有鎖,誰進(jìn)入臨界區(qū)!
- 如何理解加鎖和解鎖的本質(zhì) — 加鎖的過程是原子的!
如果線程1,申請鎖成功,進(jìn)入臨界資源,正在訪問臨界資源期間,其他線程在做什么?﹖阻塞等待
如果線程1,申請鎖成功,進(jìn)入臨界資源,正在訪問臨界資源期間,我可不可以被切換呢??絕對可以的!
當(dāng)持有鎖的線程被切走的時候,是抱著鎖被切走的,即便自己被切走了,其他線程依舊無法申請鎖成功,也便無法向后執(zhí)行!直到我最終釋放這個鎖!
所以,對于其他線程而言,有意義的鎖的狀態(tài),無非兩種1.申請鎖前⒉釋放鎖后
站在其他線程的角度,看待當(dāng)前線程持有鎖的過程,就是原子的!!
未來我們在使用鎖的時候,一定要盡量保證臨界區(qū)的粒度要非常小! 粒度:鎖中間保護(hù)代碼的多少
3.互斥量實(shí)現(xiàn)原理
經(jīng)過上面的例子,大家已經(jīng)意識到單純的 sticket++ 或者sticket-- 都不是原子的,有可能會有數(shù)據(jù)一致性問題
為了實(shí)現(xiàn)互斥鎖操作,大多數(shù)體系結(jié)構(gòu)都提供了swap或exchange指令,該指令的作用是把寄存器和內(nèi)存單元的數(shù)據(jù)相交換,由于只有一條指令,保證了原子性,即使是多處理器平臺,訪問內(nèi)存的 總線周期也有先后,一個處理器上的交換指令執(zhí)行時另一個處理器的交換指令只能等待總線周期。 現(xiàn)在我們把lock和unlock的偽代碼改一下
1.CPU內(nèi)寄存器只有一套被所有執(zhí)行流共享
2.CPU內(nèi)寄存器的內(nèi)容,是每個執(zhí)行流私有的,運(yùn)行時上下文
假如線程1先執(zhí)行,先申請鎖,將0放到寄存器中,然后將鎖的值和寄存器中的值進(jìn)行交換,即使現(xiàn)在進(jìn)行被切換,那么寄存器中的值作為上下文數(shù)據(jù)也會被線程1帶走,那么下一個線程來的時候,將寄存器中的值與內(nèi)存中鎖的值進(jìn)行交換,那么寄存器中的值還是0,線程就會掛起等待,只有線程1執(zhí)行完畢之后釋放鎖,其他線程才能夠申請到鎖,就保存了申請鎖的原子性。交換的本質(zhì):共享的數(shù)據(jù),交換到我得上下文中!!!一條匯編完成I
釋放鎖的時候,將1賦值給鎖的值,喚醒其他線程,就完成了釋放鎖的功能。
4.可重入VS線程安全
4.1.可重入和線程安全的概念
線程安全:多個線程并發(fā)同一段代碼時,不會出現(xiàn)不同的結(jié)果。常見對全局變量或者靜態(tài)變量進(jìn)行操作,并且沒有鎖保護(hù)的情況下,會出現(xiàn)該問題。
重入:同一個函數(shù)被不同的執(zhí)行流調(diào)用,當(dāng)前一個流程還沒有執(zhí)行完,就有其他的執(zhí)行流再次進(jìn)入,我們稱之為重入。一個函數(shù)在重入的情況下,運(yùn)行結(jié)果不會出現(xiàn)任何不同或者任何問題,則該函數(shù)被稱為可重入函數(shù),否則,是不可重入函數(shù)。
4.2常見的線程不安全的情況
不保護(hù)共享變量的函數(shù)
函數(shù)狀態(tài)隨著被調(diào)用,狀態(tài)發(fā)生變化的函數(shù)
返回指向靜態(tài)變量指針的函數(shù)
調(diào)用線程不安全函數(shù)的函數(shù)
4.3常見的線程安全的情況
每個線程對全局變量或者靜態(tài)變量只有讀取的權(quán)限,而沒有寫入的權(quán)限,一般來說這些線程是安全的
類或者接口對于線程來說都是原子操作
多個線程之間的切換不會導(dǎo)致該接口的執(zhí)行結(jié)果存在二義性
4.4常見不可重入的情況
調(diào)用了malloc/free函數(shù),因?yàn)閙alloc函數(shù)是用全局鏈表來管理堆的
調(diào)用了標(biāo)準(zhǔn)I/O庫函數(shù),標(biāo)準(zhǔn)I/O庫的很多實(shí)現(xiàn)都以不可重入的方式使用全局?jǐn)?shù)據(jù)結(jié)構(gòu)
可重入函數(shù)體內(nèi)使用了靜態(tài)的數(shù)據(jù)結(jié)構(gòu)
4.5常見可重入的情況
不使用全局變量或靜態(tài)變量
不使用用malloc或者new開辟出的空間
不調(diào)用不可重入函數(shù)
不返回靜態(tài)或全局?jǐn)?shù)據(jù),所有數(shù)據(jù)都有函數(shù)的調(diào)用者提供
使用本地?cái)?shù)據(jù),或者通過制作全局?jǐn)?shù)據(jù)的本地拷貝來保護(hù)全局?jǐn)?shù)據(jù)
4.6可重入與線程安全聯(lián)系
函數(shù)是可重入的,那就是線程安全的
函數(shù)是不可重入的,那就不能由多個線程使用,有可能引發(fā)線程安全問題
如果一個函數(shù)中有全局變量,那么這個函數(shù)既不是線程安全也不是可重入的。
4.7可重入與線程安全區(qū)別
可重入函數(shù)是線程安全函數(shù)的一種
線程安全不一定是可重入的,而可重入函數(shù)則一定是線程安全的。
如果將對臨界資源的訪問加上鎖,則這個函數(shù)是線程安全的,但如果這個重入函數(shù)若鎖還未釋放則會產(chǎn)生死鎖,因此是不可重入的。
5.死鎖
5.1死鎖的概念
死鎖是指在一組進(jìn)程中的各個進(jìn)程均占有不會釋放的資源,但因互相申請被其他進(jìn)程所站用不會釋放的資源而處于的一種永久等待狀態(tài)。
5.2死鎖四個必要條件
互斥條件:一個資源每次只能被一個執(zhí)行流使用
請求與保持條件:一個執(zhí)行流因請求資源而阻塞時,對已獲得的資源保持不放
不剝奪條件:一個執(zhí)行流已獲得的資源,在末使用完之前,不能強(qiáng)行剝奪
循環(huán)等待條件:若干執(zhí)行流之間形成一種頭尾相接的循環(huán)等待資源的關(guān)系
5.3如何避免死鎖
破壞死鎖的四個必要條件
加鎖順序一致
避免鎖未釋放的場景
資源一次性分配
5.4避免死鎖算法
死鎖檢測算法(了解)
銀行家算法(了解)
總結(jié):
談?wù)勊梨i:在多把鎖的場景下,我們持有自己的鎖不釋放,還要對方的鎖,對方也是如此,此時就容易造成死鎖!1.一把鎖,有可能死鎖嗎?不可能
2.為什么會有死鎖?邏輯鏈條
一定是你用了鎖<–為什么你要用鎖呢<–保證臨界資源的安全<-多錢程訪問我們可能出現(xiàn)數(shù)據(jù)不一致的問題<–多線程&全局資源<–多戰(zhàn)程大部分資源(全局的)是共享的<–多線程的特性
任何技術(shù)都有自己的邊界,是解決問題的,但有可能在解決問題的同時,一定會可能引入新的問題!
二、 Linux線程同步
1.同步概念與競態(tài)條件
同步:在保證數(shù)據(jù)安全的前提下,讓線程能夠按照某種特定的順序訪問臨界資源,從而有效避免饑餓問題,叫做同步
競態(tài)條件:因?yàn)闀r序問題,而導(dǎo)致程序異常,我們稱之為競態(tài)條件。在線程場景下,這種問題也不難理解
2.條件變量
當(dāng)一個線程互斥地訪問某個變量時,它可能發(fā)現(xiàn)在其它線程改變狀態(tài)之前,它什么也做不了。
例如一個線程訪問隊(duì)列時,發(fā)現(xiàn)隊(duì)列為空,它只能等待,只到其它線程將一個節(jié)點(diǎn)添加到隊(duì)列中。這種情
況就需要用到條件變量。
3.條件變量函數(shù)
初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict
attr);
參數(shù):
cond:要初始化的條件變量
attr:NULL
銷毀
int pthread_cond_destroy(pthread_cond_t *cond)
等待條件滿足
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
參數(shù):
cond:要在這個條件變量上等待
mutex:互斥量
喚醒等待
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
int tickets = 1000;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void *start_routine(void *args)
{
std::string name = static_cast<const char *>(args);
while (true)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
// 判斷暫時省略
std::cout << name << " -> " << tickets << std::endl;
tickets--;
pthread_mutex_unlock(&mutex);
}
}
int main()
{
// 通過條件變量控制線程的執(zhí)行
pthread_t t[5];
for (int i = 0; i < 5; i++)
{
char *name = new char[64];
snprintf(name, 64, "thread %d", i + 1);
pthread_create(t+i, nullptr, start_routine, name);
}
while (true)
{
sleep(1);
pthread_cond_signal(&cond);
std::cout << "main thread wakeup one thread..." << std::endl;
}
for (int i = 0; i < 5; i++)
{
pthread_join(t[i], nullptr);
}
return 0;
}
pthread_cond_wait
函數(shù),線程會進(jìn)入阻塞狀態(tài),并且會自動釋放已經(jīng)持有的互斥鎖。這樣其他線程就可以獲取到互斥鎖,并繼續(xù)執(zhí)行。等待條件變量的線程被喚醒后,它會重新獲取互斥鎖,然后繼續(xù)往下執(zhí)行。
在主線程中,通過調(diào)用pthread_cond_signal
函數(shù),會喚醒一個等待條件變量的線程。每個線程都會嘗試重新獲取互斥鎖并繼續(xù)執(zhí)行。這樣就實(shí)現(xiàn)了多個線程同時競爭互斥鎖的機(jī)制。
因此,雖然只有一個線程能夠獲取到互斥鎖并進(jìn)入臨界區(qū),但其他線程也有機(jī)會競爭互斥鎖,而不是一直被阻塞。這樣可以提高并發(fā)性能,讓多個線程能夠同時執(zhí)行而不是串行執(zhí)行。
我們也可以一次喚醒所有的線程:
pthread_cond_broadcast(pthread_cond_t *cond);
結(jié)果運(yùn)行如下:
為什么 pthread_cond_wait 需要互斥量?
條件等待是線程間同步的一種手段,如果只有一個線程,條件不滿足,一直等下去都不會滿足,所以必須要有一個線程通過某些操作,改變共享變量,使原先不滿足的條件變得滿足,并且友好的通知等待在條件變量上的線程。
條件不會無緣無故的突然變得滿足了,必然會牽扯到共享數(shù)據(jù)的變化。所以一定要用互斥鎖來保護(hù)。沒有互斥鎖就無法安全的獲取和修改共享數(shù)據(jù)。
按照上面的說法,我們設(shè)計(jì)出如下的代碼:先上鎖,發(fā)現(xiàn)條件不滿足,解鎖,然后等待在條件變量上不就行了,如下代碼
// 錯誤的設(shè)計(jì)
pthread_mutex_lock(&mutex);
while (condition_is_false)
{
pthread_mutex_unlock(&mutex);
//解鎖之后,等待之前,條件可能已經(jīng)滿足,信號已經(jīng)發(fā)出,但是該信號可能被錯過
pthread_cond_wait(&cond);
pthread_mutex_lock(&mutex);
}
pthread_mutex_unlock(&mutex);
由于解鎖和等待不是原子操作。調(diào)用解鎖之后, pthread_cond_wait 之前,如果已經(jīng)有其他線程獲取到互斥量,摒棄條件滿足,發(fā)送了信號,那么 pthread_cond_wait 將錯過這個信號,可能會導(dǎo)致線程永遠(yuǎn)阻塞在這個 pthread_cond_wait 。所以解鎖和等待必須是一個原子操作。int pthread_cond_wait(pthread_cond_ t *cond,pthread_mutex_ t * mutex); 進(jìn)入該函數(shù)后,會去看條件量等于0不?等于,就把互斥量變成1,直到cond_ wait返回,把條件量改成1,把互斥量恢復(fù)成原樣。
pthread_cond_wait
函數(shù)的操作可以分為以下幾步:
- 當(dāng)線程調(diào)用
pthread_cond_wait
函數(shù)時,它會首先將自己加入到條件變量的等待隊(duì)列中,并釋放已經(jīng)持有的互斥鎖。這樣其他線程就能夠獲取到互斥鎖并繼續(xù)執(zhí)行,而不會因?yàn)榛コ怄i一直被該線程占用而導(dǎo)致死鎖問題。 - 當(dāng)條件變量發(fā)出信號(如通過
pthread_cond_signal
或pthread_cond_broadcast
函數(shù))喚醒一個或多個等待在條件變量上的線程時,被喚醒的線程會嘗試重新獲取互斥鎖。 - 一旦線程獲取到互斥鎖,它就可以繼續(xù)執(zhí)行臨界區(qū)的代碼。
如果沒有互斥鎖的配合,pthread_cond_wait
函數(shù)無法正確釋放和重新獲取互斥鎖,這可能導(dǎo)致死鎖或競態(tài)條件問題。通過使用互斥鎖,pthread_cond_wait
函數(shù)可以安全地釋放和重新獲取互斥鎖,確保線程之間的同步和順序執(zhí)行。因此,在使用條件變量時,通常需要與互斥鎖配對使用以確保正確的同步機(jī)制。
4.條件變量使用規(guī)范
等待條件代碼
pthread_mutex_lock(&mutex);
while (條件為假)
pthread_cond_wait(cond, mutex);
修改條件
pthread_mutex_unlock(&mutex);
- 線程調(diào)用
pthread_mutex_lock
函數(shù)獲取互斥鎖,如果互斥鎖已經(jīng)被其他線程占用,則當(dāng)前線程將進(jìn)入阻塞狀態(tài),直到能夠獲取到互斥鎖為止。 - 然后線程進(jìn)入一個while循環(huán),判斷是否滿足特定的條件。如果不滿足,則線程調(diào)用
pthread_cond_wait
函數(shù)進(jìn)入阻塞狀態(tài),并且會自動釋放已經(jīng)持有的互斥鎖。等待條件變量的線程被喚醒后,它會重新獲取互斥鎖并繼續(xù)往下執(zhí)行。 - 當(dāng)線程被喚醒時,它會再次檢查while循環(huán)的條件是否滿足。如果不滿足,則線程會繼續(xù)阻塞等待。
- 如果while循環(huán)的條件滿足,則線程會執(zhí)行修改條件的代碼,然后調(diào)用
pthread_mutex_unlock
函數(shù)釋放互斥鎖。
通過這種方式,線程可以等待某些特定的條件滿足后再繼續(xù)執(zhí)行。同時,它也可以避免競態(tài)條件和死鎖問題的出現(xiàn)。
給條件發(fā)送信號代碼文章來源:http://www.zghlxwxcb.cn/news/detail-761639.html
pthread_mutex_lock(&mutex);
設(shè)置條件為真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);
- 線程調(diào)用
pthread_mutex_lock
函數(shù)獲取互斥鎖,如果互斥鎖已經(jīng)被其他線程占用,則當(dāng)前線程將進(jìn)入阻塞狀態(tài),直到能夠獲取到互斥鎖為止。 - 然后設(shè)置條件為真,即滿足了特定的條件。
- 接著,線程調(diào)用
pthread_cond_signal
函數(shù),向等待在條件變量上的一個線程發(fā)出信號,告訴它可以繼續(xù)執(zhí)行了。 - 最后,線程調(diào)用
pthread_mutex_unlock
函數(shù)釋放互斥鎖。
通過這樣的操作,線程在滿足特定條件后,可以通過條件變量和互斥鎖來實(shí)現(xiàn)與其他線程之間的同步。其中,pthread_cond_signal
函數(shù)用于通知等待在條件變量上的一個線程,而pthread_cond_broadcast
函數(shù)可以通知所有等待在條件變量上的線程。這樣可以確保等待在條件變量上的線程能夠及時被喚醒并繼續(xù)執(zhí)行。文章來源地址http://www.zghlxwxcb.cn/news/detail-761639.html
到了這里,關(guān)于【Linux】Linux線程互斥與同步的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!