多線程編程精髓(三)

本篇主要講Linux環(huán)境下的多線程同步內(nèi)核對象。

(1)linux線程同步之互斥體:linux互斥體的用法與windows的臨界區(qū)對象類似,使用數(shù)據(jù)結(jié)構(gòu) pthread_mutex_t表示互斥體對象(定義于pthread.h頭文件中),初始化方式有兩種:

? ? ? ? ? ? ? 1.使用 PTHREAD_MUTEX_INITIALIZER 直接給互斥體變量賦值,如:pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;

? ? ? ? ? ? ? 2.使用pthread_mutex_init函數(shù)初始化,如果互斥量是動態(tài)分配的或者需要給互斥量設(shè)置屬性,函數(shù)簽名:

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

? ? ? ? ? ? ? ? //參數(shù) mutex 即我們需要初始化的 mutex 對象的指針,參數(shù) attr 是需要設(shè)置的互斥體屬性,設(shè)置NULL表示默認(rèn)屬性PTHREAD_MUTEX_NORMAL(普通鎖),此外還有

PTHREAD_MUTEX_ERRORCHECK(檢錯鎖),PTHREAD_MUTEX_RECURSIVE(嵌套鎖),普通鎖則是線程獨占,有線程占用的情況下其他線程調(diào)用上鎖函數(shù)阻塞,檢錯鎖是已

經(jīng)上鎖的線程對互斥體對象重復(fù)加鎖,上鎖返回EDEADLK,允許同一個線程對其持有的互斥體重復(fù)加鎖,每加鎖一次互斥體對象的鎖引用就會新增一次,解鎖會減少一次,當(dāng)計數(shù)為0時

其他線程才能獲得該鎖。

? ? ? ? ? ? ?? 互斥體對象銷毀:int pthread_mutex_destroy(pthread_mutex_t* mutex); 成功則返回0 ,注意:使用 PTHREAD_MUTEX_INITIALIZER 初始化的互斥量無須銷毀,要去銷毀一

個已經(jīng)加鎖或正在被條件變量使用的互斥體對象。

? ? ? ? ? ? ?? 對于互斥體的加鎖和解鎖操作一般使用以下三個函數(shù):

? ? ? ? ? ? ? ? int ? pthread_mutex_lock(pthread_mutex_t* mutex);

? ? ? ? ? ? ? ? int ? pthread_mutex_trylock(pthread_mutex_t* mutex);

? ? ? ? ? ? ? ? int ? pthread_mutex_unlock(pthread_mutex_t* mutex);

? ? ? ? ? ?? 使用 pthread_mutexattr_settype/pthread_mutexattr_gettype 設(shè)置或獲取想要的屬性類型:

? ? ? ? ? ? ? ? int? pthread_mutexattr_settype(pthread_mutexattr_t* attr,int type);

? ? ? ? ? ? ? ? int? pthread_mutexattr_gettype(const pthread_mutexattr_t* restrictattr,int* restricttype);

如下使用例子:

? ? ? ? ? ? ? ? ?? #include<pthread.h>

? ? ? ? ? ? ? ? ? #include<stdio.h>

? ? ? ? ? ? ? ? ? #include<errno.h>?

? ? ? ? ? ? ? ? ? int? main(){

? ? ? ? ? ? ? ? ? ? ?? pthread_mutex_t mymutex;

? ? ? ? ? ? ? ? ? ? ?? pthread_mutex_init(&mymutex, NULL);

? ? ? ? ? ? ? ? ? ? ?? int ret = pthread_mutex_lock(&mymutex);

? ? ? ? ? ? ? ? ? ? ?? ret = pthread_mutex_destroy(&mymutex);

? ? ? ? ? ? ? ? ? ? ? ?? if (ret != 0)

? ? ? ? ? ? ? ? ? ? ? ?? {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (errno == EBUSY)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? printf("EBUSY\n");

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("Failed to destroy mutex.\n");

? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ret = pthread_mutex_unlock(&mymutex);

? ? ? ? ? ? ? ? ? ? ? ? ret = pthread_mutex_destroy(&mymutex);

? ? ? ? ? ? ? ? ? ? ? ?? if (ret == 0)

? ? ? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("Succeed to destroy mutex.\n");

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? return 0;

? ? ? ? ? ? ? ?? }

(2)linux線程同步之信號量:與windows的Semaphore 對象使用原理一樣,linux的信號量也可以資源多份,可同時被多個線程訪問,頭文件semaphore.h,常用的一組API函數(shù):

? ? ? ? int? sem_init(sem_t* sem,int pshared,unsigned int value); //初始化信號量,參數(shù) sem 傳入初始化信號量地址;參數(shù) pshared表示該信號量是否可以被初始化該信號量的進(jìn)程 fork 出

來的子進(jìn)程共享,取值為 0 (不可以共享)、1(可以共享);參數(shù) value 用于設(shè)置信號量初始狀態(tài)下資源的數(shù)量;初始化成功返回0,失敗返回-1;

? ? ? ? int? sem_destroy(sem_t* sem); //銷毀信號量

? ? ? ? int? sem_post(sem_t* sem);? //將信號量的資源計數(shù)加一,并解鎖sem_wait而阻塞的線程

? ? ? ? int? sem_wait(sem_t* sem);? //?如果當(dāng)前信號量資源計數(shù)為 0,函數(shù)會阻塞調(diào)用線程;直到信號量對象的資源計數(shù)大于 0 時被喚醒,喚醒后將資源計數(shù)遞減 1,然后立即返回

? ? ? ? int? sem_trywait(sem_t* sem); //sem_wait函數(shù)的非阻塞版,當(dāng)前信號量對象的資源計數(shù)等于 0,函數(shù)會立即返回不會阻塞調(diào)用線程,返回值是 ﹣1,錯誤碼 errno 被設(shè)置成 EAGAIN

? ? ? ? int? sem_timedwait(sem_t* sem,conststructtimespec* abs_timeout); // 帶有等待時間的版本,等待時間在第二個參數(shù) abs_timeout 中設(shè)置,不能設(shè)置為NULL,否則會奔潰

? ? ?? 注意:1.sem_wait、sem_trywait、sem_timedwait 函數(shù)將資源計數(shù)遞減一時會同時鎖定信號量對象,因此當(dāng)資源計數(shù)為 1 時,如果有多個線程調(diào)用 sem_wait 等函數(shù)等待該信號量

時,只會有一個線程被喚醒。當(dāng) sem_wait 函數(shù)返回時,會釋放對該信號量的鎖。

? ? ? ? ? ? ? ?? 2.sem_wait、sem_trywait、sem_timedwait 函數(shù)調(diào)用成功后返回值均為 0,調(diào)用失敗返回 ﹣1,可以通過錯誤碼 errno 獲得失敗原因。

? ? ? ? ? ? ? ?? 3.sem_wait、sem_trywait、sem_timedwait 可以被 Linux 信號中斷,被信號中斷后,函數(shù)立即返回,返回值是 ﹣1,錯誤碼 errno 為 EINTR。

(3)linux線程同步之條件變量:為了讓條件變量和互斥對象兩者為原子操作,則兩者需要同時結(jié)合使用,否則會出現(xiàn)CPU的調(diào)度導(dǎo)致線程獲得互斥對象但是卻錯過了條件變量喚醒的信

號導(dǎo)致線程阻塞。條件變量常用API函數(shù)如下:

? ? ? ? int? pthread_cond_init(pthread_cond_t* cond,const pthread_condattr_t* attr); //初始化函數(shù) 也可使用 pthread_cond_t cond = PTHREAD_COND_INITIALIZER代替;

? ? ? ? int? pthread_cond_destroy(pthread_cond_t* cond);? //銷毀函數(shù)

? ? ? ? int? pthread_cond_wait(pthread_cond_t* restrict cond,pthread_mutex_t* restrict mutex); //條件變量不滿足,線程阻塞

? ? ? ? int? pthread_cond_timedwait(pthread_cond_t* restrictcond,pthread_mutex_t* restrictmutex,const struct timespec* restrict abstime); //等待的非租塞函數(shù),指定時間返回

? ? ? ? int? pthread_cond_signal(pthread_cond_t* cond); // 一次喚醒一個線程,具體哪個線程視情況而定,返回值非0為失敗

? ? ? ? int? pthread_cond_broadcast(pthread_cond_t* cond);? //廣播喚醒,一次喚醒多個線程 ,返回值非0為失敗

? ? ? 注意:1.當(dāng) pthread_cond_wait 函數(shù)阻塞時,它會釋放其綁定的互斥體,并阻塞線程,因此在調(diào)用該函數(shù)前應(yīng)該對互斥體有個加鎖操作,當(dāng)收到條件信號時, pthread_cond_wait?

會返回并對其綁定的互斥體進(jìn)行加鎖,因此在其下面一定有個對互斥體進(jìn)行解鎖的操作。

? ? ? ? ? ? ? ? 2.條件變量的虛假喚醒:操作系統(tǒng)可能會在一些情況下喚醒條件變量,即使沒有其他線程向條件變量發(fā)送信號,等待此條件變量的線程也有可能會醒來。pthread_cond_wait?

是 futex 系統(tǒng)調(diào)用,屬于阻塞型的系統(tǒng)調(diào)用,當(dāng)系統(tǒng)調(diào)用被信號中斷的時候,會返回 ﹣1,并且把 errno 錯誤碼置為 EINTR。很多這種系統(tǒng)調(diào)用為了防止被信號中斷都會重啟系統(tǒng)調(diào)用

(即再次調(diào)用一次這個函數(shù))。

? ? ? ? ? ? ? 3.如果一個條件變量信號條件產(chǎn)生時(調(diào)用 pthread_cond_signal 或pthread_cond_broadcast),沒有相關(guān)的線程調(diào)用 pthread_cond_wait 捕獲該信號,那么該信號條件就

會永久性地丟失了,再次調(diào)用 pthread_cond_wait 會導(dǎo)致永久性的阻塞,因此,一定要確保等待的線程在產(chǎn)生條件變量信號的線程發(fā)送條件信號之前調(diào)用 pthread_cond_wait。?

(4) linux線程同步之讀寫鎖:讀寫鎖在 Linux 系統(tǒng)中使用類型 pthread_rwlock_t 表示,?

? ? ? ? ? ? 讀鎖用于共享模式:

? ? ? ? ?? 如果當(dāng)前讀寫鎖已經(jīng)被某線程以讀模式占有了,其他線程調(diào)用pthread_rwlock_rdlock(請求讀鎖)會立刻獲得讀鎖;

? ? ? ? ?? 如果當(dāng)前讀寫鎖已經(jīng)被某線程以讀模式占有了,其他線程調(diào)用pthread_rwlock_wrlock(請求寫鎖)會陷入阻塞。

? ? ? ? ?? 寫鎖用的是獨占模式:

? ? ? ? ? 如果當(dāng)前讀寫鎖被某線程以寫模式占有,無論調(diào)用pthread_rwlock_rdlock還是pthread_rwlock_wrlock都會陷入阻塞,即寫模式下不允許任何讀鎖請求通過,也不允許任何寫鎖

請求通過,讀鎖請求和寫鎖請求都要陷入阻塞,直到線程釋放寫鎖。

? ? ? ? ?? 讀寫鎖初始化和銷毀的API:

? ? ? ? ?? int? pthread_rwlock_init(pthread_rwlock_t* rwlock,const pthread_rwlockattr_t* attr); //參數(shù) rwlock 即需要初始化和銷毀的讀寫鎖對象的地址,參數(shù) attr 用于設(shè)置讀寫鎖的屬性,設(shè)置

NULL表示默認(rèn)屬性,返回非0 為失敗,當(dāng)不需要動態(tài)創(chuàng)建或者設(shè)置非默認(rèn)屬性的讀寫鎖對象,可使用?pthread_rwlock_t myrwlock = PTHREAD_RWLOCK_INITIALIZER; 初始化

? ? ? ? ?? int? pthread_rwlock_destroy(pthread_rwlock_t* rwlock); //銷毀讀寫鎖

? ? ? ? ? 請求讀鎖和寫鎖API數(shù):

? ? ? ? ?? int? pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);

? ? ? ? ?? int? pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock);

? ? ? ? ?? int? pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock,conststructtimespec* abstime);

? ? ? ? ?? int? pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);

? ? ? ? ?? int? pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock);

? ? ? ? ?? int? pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock,conststructtimespec* abstime);

? ? ? ? ? 無論是讀鎖還是寫鎖,鎖的釋放都是一個接口:

? ? ? ? ? int? pthread_rwlock_unlock(pthread_rwlock_t* rwlock);

? ? ? ? ? 讀寫鎖的屬性類型是 pthread_rwlockattr_t ,glibc 引入了如下接口來查詢和改變讀寫鎖的類型:

? ? ? ? ? int? pthread_rwlockattr_setkind_np(pthread_rwlockattr_t* attr,intpref);

? ? ? ? ? int? pthread_rwlockattr_getkind_np(constpthread_rwlockattr_t* attr,int* pref);

? ? ? ? ? pthread_rwlockattr_setkind_np 的第二個參數(shù) pref 即設(shè)置讀寫鎖的類型,其取值有如下幾種:

? ? ? ? enum{

? ? ? ? PTHREAD_RWLOCK_PREFER_READER_NP, ? //讀者優(yōu)先(即同時請求讀鎖和寫鎖時,請求讀鎖的線程優(yōu)先獲得鎖)?

? ? ? ? PTHREAD_RWLOCK_PREFER_WRITER_NP, //不要被名字所迷惑,也是讀者優(yōu)先

? ? ?? PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,? ? //寫者優(yōu)先(即同時請求讀鎖和寫鎖時,請求寫鎖的線程優(yōu)先獲得鎖) ? ? ? ? ? ?

? ? ? ? PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP // 默認(rèn),讀者優(yōu)先

? ? ? ? };

? ? ?? 初始化和銷毀 pthread_rwlockattr_t 對象:

? ? ?? int? pthread_rwlockattr_init(pthread_rwlockattr_t* attr);

? ? ?? in? tpthread_rwlockattr_destroy(pthread_rwlockattr_t* attr);

? ? ?? 初始化一個寫者優(yōu)先的讀寫鎖的例子:

? ? ?? pthread_rwlockattr_t attr;

? ? ?? pthread_rwlockattr_init(&attr);

? ? ?? pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);pthread_rwlock_t rwlock;

? ? ?? pthread_rwlock_init(&rwlock, &attr);

(5)C++11/14/17線程資源同步對象:C/C++提供的直接使用操作系統(tǒng)的功能函數(shù)雖然強(qiáng)大,也存在功能限制,同樣的代碼不能通知兼容linux和windows,因此C++11以及后續(xù)更新封裝

同步輔助類std::mutex、std::condition_variable、std::lock_guard、std::unique_lock,極大的方便了跨平臺開發(fā)。

? ? ? ?? 常用的比如 std::mutex (C++11互斥對象)、std::shared_mutex(C++17共享的互斥量),均提供了加鎖(lock)、嘗試加鎖(trylock)和解鎖(unlock)的方法,為了避免死鎖,例

如std::mutex.lock() 和 std::mutex::unlock() 方法需要成對使用,為了防止函數(shù)出口過多導(dǎo)致加鎖后沒有解鎖導(dǎo)致死鎖,推薦 RAII 技術(shù)封裝加鎖和解鎖的兩個接口,同時C++11也提供如

下封裝:

? ? ? ?? 互斥量管理 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 版本 ? ? ? ? ? ? ? ? ? ? ? ?? 作用

? ? ? ? lock_guard ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? C++11 ? ? ? ? ? ? ? ?? 基于作用域的互斥量管理

? ? ? ? unique_lock ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? C++11 ? ? ? ? ? ? ? ? ? 更加靈活的互斥量管理

? ? ? ? shared_lock ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? C++14 ? ? ? ? ? ? ? ? ?? 共享互斥量的管理

? ? ? ? scope_lock ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? C++17 ? ? ? ? ? ? ? ? ?? 多互斥量避免死鎖的管理

? ? ? ? 注意:1.比如? void func(){

? ? ? ? ? ? ? ? ? ? ? ? ? ? std::lock_guard<std::mutex> guard(mymutex);

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //在這里放被保護(hù)的資源操作

? ? ? ? ? ? ? ? ? ? ? ? ?? }?

? ? ? ?? mymutex 的類型是 std::mutex,在 guard 對象的構(gòu)造函數(shù)中,會自動調(diào)用 mymutex.lock() 方法加鎖,當(dāng)該函數(shù)出了作用域后,調(diào)用 guard 對象時析構(gòu)函數(shù)時會自動調(diào)用 ?

mymutex.unlock() 方法解鎖 ,因此 mymutex 生命周期必須長于函數(shù) func 的作用域。

? ? ? ? ? ? ? ? ? 2.重復(fù)加鎖可能會造成程序奔潰,如果一個 std::mutex 對象已經(jīng)調(diào)用了 lock() 方法,再次調(diào)用時,其行為是未定義的,“行為未定義”即在不同平臺上可能會有不同的行為。

? ? ? ? std::condition_variable表示條件變量,與linux環(huán)境下的原生條件變量一樣,提供了等待條件變量滿足的 wait 系列方法(wait、wait_for、wait_until 方法),發(fā)送條件信號使用?

notify 方法(notify_one 和 notify_all 方法),當(dāng)然使用 std::condition_variable 對象時需要綁定一個 std::unique_lock 或 std::lock_guard 對象,但是C++ 11 中 std::condition_variable 不

再需要顯式調(diào)用方法初始化和銷毀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內(nèi)容

  • 多線程系列文章源碼頭文件內(nèi)容: #include #include #include 作為程序員,就是要減少重復(fù)勞...
    batbattle閱讀 942評論 0 1
  • Q:為什么出現(xiàn)多線程? A:為了實現(xiàn)同時干多件事的需求(并發(fā)),同時進(jìn)行著下載和頁面UI刷新。對于處理器,為每個線...
    幸福相依閱讀 1,597評論 0 2
  • Linux 多線程 - 線程異步與同步機(jī)制 I. 同步機(jī)制 線程間的同步機(jī)制主要包括三個: 互斥鎖:以排他的方式,...
    不愛吃飯的牛牛閱讀 1,408評論 0 1
  • 線程基礎(chǔ) 線程是進(jìn)程的一個執(zhí)行單元,執(zhí)行一段程序片段,線程共享全局變量;線程的查看可以使用命令或者文件來進(jìn)行查看;...
    秋風(fēng)弄影閱讀 745評論 0 0
  • 摘要 線程概念,線程與進(jìn)程的區(qū)別與聯(lián)系學(xué)會線程控制,線程創(chuàng)建,線程終止,線程等待了解線程分離與線程安全學(xué)會線程同步...
    狼之足跡閱讀 472評論 2 3