引言
在上一篇文章中,我們?cè)敿?xì)探討了多線程編程的基礎(chǔ)概念,包括線程互斥、互斥鎖以及死鎖和資源饑餓等問題。我們了解到,在多線程環(huán)境下,為了防止數(shù)據(jù)競爭和保證程序的正確性,需要采用一定的同步機(jī)制來協(xié)調(diào)線程之間的執(zhí)行順序。本篇文章將繼續(xù)深入探討多線程編程中的另一組關(guān)鍵概念:線程同步、條件變量和線程安全。
在這篇文章中,我們將具體介紹線程同步的技術(shù)和模式,探討條件變量的工作原理以及如何在實(shí)際編程中正確使用它們來避免競態(tài)條件和提高程序效率。同時(shí),我們還將分析線程安全的概念,并通過示例展示如何編寫線程安全的代碼,以確保多線程程序的可靠性和穩(wěn)定性。隨著對(duì)這些概念的深入理解,我們將能夠更加熟練地掌握多線程編程,打造出更加健壯和高效的軟件系統(tǒng)。
一、線程同步
1. 競態(tài)條件的概念
競態(tài)條件(Race Condition)是并發(fā)編程中的一個(gè)重要概念,它指的是程序的輸出或行為依賴于事件或線程的時(shí)序。在多線程環(huán)境中,如果多個(gè)線程共享某些數(shù)據(jù),并且它們?cè)噲D同時(shí)讀寫這些數(shù)據(jù)而沒有適當(dāng)?shù)耐綑C(jī)制來協(xié)調(diào)這些操作,就可能出現(xiàn)競態(tài)條件。
簡單來說,當(dāng)兩個(gè)或更多的線程訪問共享數(shù)據(jù),并且至少有一個(gè)線程在修改這些數(shù)據(jù)時(shí),如果線程之間的執(zhí)行順序會(huì)影響最終的結(jié)果,那么就存在競態(tài)條件。由于線程調(diào)度通常由操作系統(tǒng)進(jìn)行,而且具有一定的隨機(jī)性,因此競態(tài)條件可能導(dǎo)致程序行為不可預(yù)測,有時(shí)候甚至非常難以復(fù)現(xiàn)和調(diào)試。
競態(tài)條件的一個(gè)典型例子是“檢查后行動(dòng)”(check-then-act)操作,其中線程檢查某個(gè)條件(如資源是否可用),然后基于這個(gè)條件采取行動(dòng)。如果在檢查和行動(dòng)之間的時(shí)間窗口內(nèi),另一個(gè)線程改變了條件(如搶占了資源),那么第一個(gè)線程的行動(dòng)可能基于錯(cuò)誤的假設(shè)。
另一個(gè)常見的競態(tài)條件是“讀-改-寫”(read-modify-write)操作,這涉及到讀取一個(gè)變量的值,對(duì)其進(jìn)行修改,然后寫回新值。如果兩個(gè)線程同時(shí)執(zhí)行這樣的操作,而且它們的讀取和寫入操作是交織在一起的,那么最終寫回的值可能只反映了其中一個(gè)線程的修改,而另一個(gè)線程的修改則丟失了。
為了避免競態(tài)條件,我們需要使用線程同步機(jī)制,如互斥鎖、信號(hào)量、條件變量等,來確保在任何時(shí)刻只有一個(gè)線程能夠訪問臨界區(qū)的代碼。通過這種方式,可以序列化對(duì)共享資源的訪問,從而避免不確定的時(shí)序和數(shù)據(jù)沖突,保證程序的正確性和穩(wěn)定性。
2. 線程同步的概念
線程同步是指在多線程環(huán)境中,控制不同線程之間的執(zhí)行順序,確保它們能夠有序地共享資源和協(xié)調(diào)工作的一系列機(jī)制和方法。當(dāng)多個(gè)線程訪問共享資源時(shí),如果沒有適當(dāng)?shù)耐剑涂赡馨l(fā)生競態(tài)條件(Race Condition),導(dǎo)致數(shù)據(jù)不一致、程序錯(cuò)誤甚至崩潰。
為了防止這些問題,線程同步提供了一種方式,使得在任何時(shí)刻只有一個(gè)線程可以訪問到臨界區(qū)(Critical Section)。臨界區(qū)是指那些訪問共享資源的代碼段,這些資源可能是內(nèi)存、文件或者其他外部狀態(tài)。通過線程同步,我們可以確保每次只有一個(gè)線程可以操作臨界區(qū)內(nèi)的共享資源,從而避免非預(yù)期的交互和數(shù)據(jù)沖突。
二、條件變量
條件變量是一種同步原語,它用于線程間的通信,使得一個(gè)線程能夠在某個(gè)特定條件不滿足時(shí)掛起(等待),直到另一個(gè)線程更新了這個(gè)條件并通知等待的線程。條件變量通常與互斥鎖(mutex)一起使用,以避免競態(tài)條件,并確保數(shù)據(jù)的一致性。
1. 條件變量函數(shù)
?使用前提
在Linux環(huán)境下,使用條件變量相關(guān)的函數(shù)需要包含<pthread.h>
頭文件:
#include <pthread.h>
<pthread.h>
頭文件中定義了所有與POSIX線程相關(guān)的數(shù)據(jù)類型、函數(shù)原型和宏。這包括了條件變量的操作函數(shù)、互斥鎖的操作函數(shù)以及線程創(chuàng)建和控制的函數(shù)。
當(dāng)編譯使用了 <pthread.h>
的程序時(shí),通常需要鏈接線程庫,這可以通過在編譯命令中添加 -lpthread
選項(xiàng)來實(shí)現(xiàn)。例如:
gcc program.c -o program -lpthread
這條命令會(huì)編譯 program.c
文件,并將POSIX線程庫鏈接到生成的可執(zhí)行文件 program
中。
(1)初始化條件變量
在POSIX線程(pthreads)庫中,條件變量可以通過兩種方式進(jìn)行初始化:
-
靜態(tài)初始化:使用預(yù)定義的宏
PTHREAD_COND_INITIALIZER
來初始化條件變量。這是在程序開始執(zhí)行之前,即編譯時(shí)期就已經(jīng)完成的初始化。示例代碼:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-
動(dòng)態(tài)初始化:使用函數(shù)
pthread_cond_init()
在運(yùn)行時(shí)動(dòng)態(tài)地初始化條件變量。這種方式允許你指定條件變量的屬性。示例代碼:
pthread_cond_t cond; int ret = pthread_cond_init(&cond, NULL); // 使用NULL作為屬性參數(shù),表示默認(rèn)屬性 if (ret != 0) { // 錯(cuò)誤處理 }
在動(dòng)態(tài)初始化的情況下,如果你想要設(shè)置特定的條件變量屬性,可以創(chuàng)建一個(gè) pthread_condattr_t
類型的變量,并使用 pthread_condattr_init()
和相關(guān)函數(shù)來設(shè)置所需的屬性。之后,將這個(gè)屬性變量傳遞給 pthread_cond_init()
函數(shù)。
不論是靜態(tài)還是動(dòng)態(tài)初始化,初始化后的條件變量都處于未信號(hào)化的狀態(tài),等待被 pthread_cond_signal()
或 pthread_cond_broadcast()
函數(shù)喚醒。
(2)等待條件滿足
pthread_cond_wait
函數(shù)是POSIX線程庫中用于等待條件變量的函數(shù)。它的作用是阻塞調(diào)用線程直到指定的條件變量被信號(hào)化。在等待期間,pthread_cond_wait
會(huì)自動(dòng)釋放與條件變量相關(guān)聯(lián)的互斥鎖,并且在條件變量被信號(hào)化后重新獲取互斥鎖。
pthread_cond_wait
函數(shù)的原型:
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
參數(shù)解釋:
-
cond
:指向需要等待的條件變量的指針。 -
mutex
:指向當(dāng)前線程已鎖定的互斥鎖的指針,必須在調(diào)用pthread_cond_wait
之前由線程鎖定。
返回值:
- 如果函數(shù)成功,返回0。
- 如果失敗,將返回一個(gè)錯(cuò)誤碼(非零值)。
使用說明
- 線程在調(diào)用
pthread_cond_wait
之前,必須確保已經(jīng)鎖定了mutex
互斥鎖。 - 調(diào)用
pthread_cond_wait
后,線程會(huì)阻塞,并且mutex
互斥鎖被自動(dòng)釋放,以允許其他線程操作條件和互斥鎖。 - 當(dāng)其他線程對(duì)條件變量調(diào)用
pthread_cond_signal
或pthread_cond_broadcast
時(shí),等待的線程會(huì)被喚醒。 - 被喚醒的線程在返回前將重新獲取
mutex
互斥鎖。這意味著當(dāng)pthread_cond_wait
返回時(shí),線程已經(jīng)再次鎖定了mutex
。 - 因?yàn)榭赡苡卸鄠€(gè)線程在等待同一個(gè)條件變量,所以即使線程被喚醒,也不能假設(shè)條件已經(jīng)滿足。通常需要在循環(huán)中調(diào)用
pthread_cond_wait
來重新檢查條件。
示例代碼
// 假設(shè)已經(jīng)聲明并初始化了cond和mutex
pthread_mutex_lock(&mutex);
while (condition_is_not_met)
{
pthread_cond_wait(&cond, &mutex);
}
// 此時(shí)condition_is_met為真,可以執(zhí)行依賴于該條件的代碼
pthread_mutex_unlock(&mutex);
在這個(gè)示例中,線程首先鎖定互斥鎖mutex
,然后在一個(gè)循環(huán)中檢查條件是否滿足。如果條件不滿足,線程調(diào)用pthread_cond_wait
等待條件變量cond
。當(dāng)條件變量被其他線程信號(hào)化時(shí),線程將被喚醒,并在重新獲得互斥鎖后繼續(xù)執(zhí)行。
(3)喚醒等待
pthread_cond_broadcast
和 pthread_cond_signal
函數(shù)都是用來喚醒等待特定條件變量的線程。它們的區(qū)別在于喚醒等待線程的數(shù)量。
pthread_cond_broadcast()
pthread_cond_broadcast
函數(shù)喚醒所有等待特定條件變量的線程。如果沒有線程在等待,調(diào)用此函數(shù)不會(huì)有任何效果。
函數(shù)原型如下:
int pthread_cond_broadcast(pthread_cond_t *cond);
參數(shù)解釋:
-
cond
:指向需要廣播信號(hào)的條件變量的指針。
返回值:
- 如果函數(shù)成功,返回0。
- 如果失敗,將返回一個(gè)錯(cuò)誤碼(非零值)。
pthread_cond_signal()
與pthread_cond_broadcast
不同,pthread_cond_signal
函數(shù)只喚醒一個(gè)正在等待特定條件變量的線程。如果有多個(gè)線程在等待,系統(tǒng)選擇一個(gè)線程喚醒。選擇哪個(gè)線程通常取決于線程調(diào)度策略,程序員無法控制。
函數(shù)原型如下:
int pthread_cond_signal(pthread_cond_t *cond);
參數(shù)解釋:
-
cond
:指向需要發(fā)送信號(hào)的條件變量的指針。
返回值:
- 如果函數(shù)成功,返回0。
- 如果失敗,將返回一個(gè)錯(cuò)誤碼(非零值)。
使用說明
- 在調(diào)用
pthread_cond_signal
或pthread_cond_broadcast
之前,通常需要鎖定與條件變量相關(guān)聯(lián)的互斥鎖。 - 調(diào)用這些函數(shù)后,互斥鎖可以被釋放,以便喚醒的線程可以繼續(xù)執(zhí)行。
- 喚醒的線程將嘗試重新獲取互斥鎖,一旦獲取成功,它們就可以檢查條件是否滿足并繼續(xù)執(zhí)行。
示例代碼
// 假設(shè)已經(jīng)聲明并初始化了cond和mutex
pthread_mutex_lock(&mutex);
// 更新條件并可能修改共享資源
condition_met = 1;
// 喚醒所有等待cond的線程
pthread_cond_broadcast(&cond);
// 或者,只喚醒至少一個(gè)等待cond的線程
// pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
在這個(gè)示例中,線程首先鎖定互斥鎖mutex
,然后更新條件變量相關(guān)的條件。之后,使用pthread_cond_broadcast
或pthread_cond_signal
來喚醒等待該條件變量的線程。最后,線程解鎖互斥鎖。
(4)銷毀條件變量
銷毀條件變量是指在條件變量不再需要時(shí),釋放它所占用的資源。在POSIX線程(pthreads)庫中,可以使用 pthread_cond_destroy
函數(shù)來銷毀一個(gè)條件變量。
pthread_cond_destroy
函數(shù)的原型:
int pthread_cond_destroy(pthread_cond_t *cond);
參數(shù)解釋:
-
cond
:指向需要銷毀的條件變量的指針。
返回值:
- 如果函數(shù)成功,返回0。
- 如果失敗,將返回一個(gè)錯(cuò)誤碼(非零值)。
使用說明
- 在調(diào)用
pthread_cond_destroy
之前,必須確保沒有線程正在等待或即將等待條件變量。否則,行為是未定義的,并且可能會(huì)導(dǎo)致程序崩潰或其他錯(cuò)誤。 - 通常,在動(dòng)態(tài)初始化的條件變量不再需要時(shí)調(diào)用
pthread_cond_destroy
。對(duì)于靜態(tài)初始化的條件變量,如果沒有分配額外的資源,則可以不調(diào)用pthread_cond_destroy
。 - 一旦條件變量被銷毀,你應(yīng)該避免再次使用它,除非它被重新初始化。
示例代碼
// 假設(shè) cond 是一個(gè)之前已經(jīng)初始化的條件變量
int ret = pthread_cond_destroy(&cond);
if (ret != 0)
{
// 錯(cuò)誤處理
}
在這個(gè)示例中,cond
是一個(gè)先前已經(jīng)初始化并且現(xiàn)在不再需要的條件變量。通過調(diào)用 pthread_cond_destroy
來銷毀它,從而釋放可能分配的資源。如果銷毀過程中出現(xiàn)錯(cuò)誤,可以根據(jù)返回的錯(cuò)誤碼進(jìn)行相應(yīng)的錯(cuò)誤處理。
2. 條件變量使用規(guī)范
條件變量的運(yùn)行機(jī)制基于兩個(gè)主要操作:等待(wait)和通知(signal/broadcast)。
(1)條件變量的使用流程
-
等待條件(Waiting for a Condition):
- 線程首先獲取與條件變量關(guān)聯(lián)的互斥鎖。
- 線程檢查某個(gè)條件是否滿足。如果條件不滿足,線程將進(jìn)入等待狀態(tài),并且原子地釋放互斥鎖,這樣其他線程就可以獲取互斥鎖來更改條件。
- 當(dāng)條件變量收到通知后,線程被喚醒,重新嘗試獲取互斥鎖。一旦獲取到鎖,線程將再次檢查條件是否滿足,以防在等待期間條件發(fā)生了變化。
-
通知等待線程(Notifying Waiting Threads):
- 另一個(gè)線程在更改了條件后,會(huì)獲取相同的互斥鎖。
- 在保持互斥鎖的情況下,該線程更新條件。
- 更新完畢后,線程通過條件變量發(fā)送通知,表示條件已經(jīng)改變。通知操作有兩種形式:
-
signal
:喚醒至少一個(gè)等待該條件變量的線程。 -
broadcast
:喚醒所有等待該條件變量的線程。
-
-
重新檢查條件(Rechecking the Condition):
- 被喚醒的線程在從等待狀態(tài)返回時(shí)需要重新獲得之前釋放的互斥鎖。
- 一旦鎖被重新獲得,線程應(yīng)該再次檢查條件,因?yàn)樵诙鄠€(gè)線程等待相同條件的情況下,條件可能已經(jīng)再次變?yōu)榧佟?/li>
(2)條件變量的使用注意事項(xiàng)
- 使用條件變量時(shí),應(yīng)當(dāng)始終與互斥鎖配合使用,以防止競態(tài)條件。
- 必須在修改條件之前獲取互斥鎖,并在修改完畢后釋放互斥鎖。
- 在等待條件變量時(shí),程序應(yīng)該處于循環(huán)中檢查條件,即使被
signal
或broadcast
喚醒,也應(yīng)重新檢查條件是否真正滿足。 - 條件變量的等待和通知操作必須在同一個(gè)互斥鎖保護(hù)下進(jìn)行,以確保數(shù)據(jù)的一致性。
3. 使用條件變量的示例
#include <pthread.h>
#include <stdio.h>
// 定義全局的條件變量和互斥鎖
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_function(void *arg)
{
// 獲取互斥鎖
pthread_mutex_lock(&mutex);
// 等待條件變量
pthread_cond_wait(&cond, &mutex);
// 做一些工作...
printf("Received signal\n");
// 釋放互斥鎖
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
pthread_t thread_id;
// 創(chuàng)建新線程
pthread_create(&thread_id, NULL, thread_function, NULL);
// 做一些工作...
sleep(1); // 等待一段時(shí)間,模擬工作
// 發(fā)送信號(hào)給等待的線程
pthread_cond_signal(&cond);
// 等待線程結(jié)束
pthread_join(thread_id, NULL);
// 清理資源
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
這個(gè)示例中,主線程創(chuàng)建了一個(gè)新線程,并通過條件變量發(fā)送信號(hào)。新線程在接收到信號(hào)后開始執(zhí)行打印操作。
三、線程安全
1. 概念
線程安全指的是當(dāng)多個(gè)線程同時(shí)訪問某個(gè)功能、對(duì)象或變量時(shí),系統(tǒng)能夠確保這個(gè)功能、對(duì)象或變量仍然能夠如預(yù)期般正常工作。具體來說,一個(gè)線程安全的程序?qū)τ诓l(fā)訪問沒有任何副作用,不會(huì)出現(xiàn)數(shù)據(jù)競爭、死鎖等問題,可以正確地處理多線程同時(shí)訪問的情況。
2. 常見的線程不安全的情況
線程不安全的情況通常發(fā)生在多個(gè)線程并發(fā)訪問共享資源時(shí),由于缺乏適當(dāng)?shù)耐交蚧コ鈾C(jī)制,導(dǎo)致出現(xiàn)意外的結(jié)果。以下是一些常見的線程不安全的情況:
-
競態(tài)條件(Race Conditions):當(dāng)多個(gè)線程試圖同時(shí)訪問和修改共享的數(shù)據(jù),而沒有足夠的同步保護(hù)時(shí),會(huì)導(dǎo)致競態(tài)條件。這可能導(dǎo)致數(shù)據(jù)損壞或不一致的結(jié)果。
-
數(shù)據(jù)競爭(Data Races):當(dāng)至少兩個(gè)線程同時(shí)訪問相同的內(nèi)存位置,其中至少一個(gè)是寫操作時(shí),且沒有適當(dāng)?shù)耐綍r(shí),就會(huì)發(fā)生數(shù)據(jù)競爭。這可能導(dǎo)致未定義的行為和程序崩潰。
-
死鎖(Deadlock):當(dāng)兩個(gè)或多個(gè)線程互相持有對(duì)方所需的資源,并且在等待對(duì)方釋放資源時(shí)都不釋放自己的資源時(shí),就會(huì)產(chǎn)生死鎖。這將導(dǎo)致多個(gè)線程永遠(yuǎn)無法繼續(xù)執(zhí)行。
-
活鎖(Livelock):類似于死鎖,但線程們不斷重試某個(gè)操作,卻始終無法取得進(jìn)展,導(dǎo)致系統(tǒng)無法正常工作。
-
非原子操作:當(dāng)一個(gè)操作需要多個(gè)步驟完成,而這些步驟中間被其他線程打斷,可能導(dǎo)致數(shù)據(jù)狀態(tài)處于不一致的狀態(tài)。
-
資源泄露:當(dāng)線程在使用完資源后沒有正確釋放,導(dǎo)致資源泄露,可能最終耗盡系統(tǒng)資源。
-
不一致的狀態(tài):當(dāng)多個(gè)線程并發(fā)修改共享狀態(tài)時(shí),由于缺乏同步機(jī)制,可能導(dǎo)致狀態(tài)變得不一致,違反程序的預(yù)期行為。
以上情況都代表了典型的線程不安全問題,編寫多線程程序時(shí)需要格外注意避免這些問題的發(fā)生。為了解決這些問題,可以使用鎖、原子操作、條件變量等同步機(jī)制來確保線程安全,以及遵循良好的并發(fā)編程實(shí)踐。
3. 常見的線程安全的情況
-
不可變對(duì)象(Immutable Objects):不可變對(duì)象在創(chuàng)建后無法被修改,因此多個(gè)線程同時(shí)訪問不會(huì)引發(fā)線程安全問題。例如,Java中的String類就是不可變對(duì)象。
-
線程本地存儲(chǔ)(Thread-Local Storage):每個(gè)線程都有自己獨(dú)立的變量副本,不會(huì)被其他線程共享,從而避免了線程安全問題。可以使用ThreadLocal類來實(shí)現(xiàn)線程本地存儲(chǔ)。
-
局部變量(Local Variables):局部變量是在每個(gè)線程的棧幀中創(chuàng)建的,每個(gè)線程擁有自己的副本,不存在線程安全問題。
-
同步容器(Synchronized Containers):某些容器類(如Vector、Hashtable)提供了內(nèi)部同步機(jī)制,可以安全地在多線程環(huán)境下使用。這些容器會(huì)確保對(duì)它們的操作是原子的,并且提供了線程安全的迭代器。
-
并發(fā)容器(Concurrent Containers):Java中的ConcurrentHashMap、ConcurrentLinkedQueue等并發(fā)容器提供了高效的線程安全操作。它們使用了復(fù)雜的算法和數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)高性能的并發(fā)訪問。
-
使用互斥鎖(Mutex)或同步機(jī)制:通過在多個(gè)線程訪問共享資源時(shí)使用互斥鎖、讀寫鎖等同步機(jī)制,可以保證線程安全。這樣在任意時(shí)刻只有一個(gè)線程能夠訪問共享資源。
-
原子操作(Atomic Operations):某些編程語言提供了原子操作,這些操作是不可中斷的,可以保證在多線程環(huán)境下的原子性。例如,Java中的AtomicInteger類提供了原子操作的整型變量。
-
使用并發(fā)編程庫和框架:一些現(xiàn)代編程語言和框架提供了豐富的并發(fā)編程工具和庫,如Java中的java.util.concurrent包,可以更方便地實(shí)現(xiàn)線程安全。
4. 可重入與線程安全的關(guān)系(八股文)
(1)可重入與線程安全的聯(lián)系
- 函數(shù)是可重入的,那就是線程安全的。
- 函數(shù)是不可重入的,那就不能由多個(gè)線程使用,有可能引發(fā)線程安全問題。
- 如果一個(gè)函數(shù)中有全局變量,那么這個(gè)函數(shù)既不是線程安全也不是可重入的。
(2)可重入與線程安全的區(qū)別
- 可重入函數(shù)是線程安全函數(shù)的一種。
- 線程安全不一定是可重入的,而可重入函數(shù)則一定是線程安全的。
- 如果將對(duì)臨界資源的訪問加上鎖,則這個(gè)函數(shù)是線程安全的,但如果這個(gè)重入函數(shù)若鎖還未釋放則會(huì)產(chǎn)生死鎖,因此是不可重入的。
溫馨提示
感謝您對(duì)博主文章的關(guān)注與支持!如果您喜歡這篇文章,可以點(diǎn)贊、評(píng)論和分享給您的同學(xué),這將對(duì)我提供巨大的鼓勵(lì)和支持。另外,我計(jì)劃在未來的更新中持續(xù)探討與本文相關(guān)的內(nèi)容。我會(huì)為您帶來更多關(guān)于Linux以及C++編程技術(shù)問題的深入解析、應(yīng)用案例和趣味玩法等。如果感興趣的話可以關(guān)注博主的更新,不要錯(cuò)過任何精彩內(nèi)容!文章來源:http://www.zghlxwxcb.cn/news/detail-752621.html
再次感謝您的支持和關(guān)注。我們期待與您建立更緊密的互動(dòng),共同探索Linux、C++、算法和編程的奧秘。祝您生活愉快,排便順暢!文章來源地址http://www.zghlxwxcb.cn/news/detail-752621.html
到了這里,關(guān)于【探索Linux】—— 強(qiáng)大的命令行工具 P.21(多線程 | 線程同步 | 條件變量 | 線程安全)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!