新聞中心
在多線程編程中,線程之間的同步和互斥是非常重要的話題,特別是在多個線程需要同時訪問共享資源的情況下,同步和互斥更是不可或缺的。在Linux系統(tǒng)下,有多種方法可以實現(xiàn)線程的同步和互斥,下面將介紹幾種較為常見的方法。

一、互斥鎖
互斥鎖也稱為互斥量,是一種用于保護(hù)共享資源的鎖。它可以通過對于需要訪問共享資源的線程進(jìn)行加鎖和解鎖的操作來保證共享資源的互斥性。在Linux系統(tǒng)下,可以使用pthread_mutex_t來定義互斥鎖。下面是一個簡單的互斥鎖的使用示例:
“`c
#include
#include
pthread_mutex_t mutex;
int shared_data = 0;
void *worker(void *arg) {
pthread_mutex_lock(&mutex);
shared_data += 1;
printf(“Update shared data to %d\n”, shared_data);
pthread_mutex_unlock(&mutex);
return NULL;
}
int mn(int argc, char *argv[]) {
pthread_t t1, t2;
pthread_mutex_init(&mutex, NULL);
pthread_create(&t1, NULL, worker, NULL);
pthread_create(&t2, NULL, worker, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
“`
在上面的示例中,定義了一個全局變量shared_data和一個互斥鎖mutex。在worker函數(shù)中,首先調(diào)用`pthread_mutex_lock`來申請互斥鎖,然后對共享資源shared_data進(jìn)行更新,最后調(diào)用`pthread_mutex_unlock`來釋放互斥鎖。在mn函數(shù)中,創(chuàng)建了兩個線程分別執(zhí)行worker函數(shù),并且在最后調(diào)用了`pthread_mutex_destroy`來銷毀互斥鎖。
二、條件變量
條件變量是一種能夠支持在共享資源滿足某種特定條件時,讓線程在等待狀態(tài)下暫停自己運行的機制。在Linux系統(tǒng)下,可以使用`pthread_cond_t`來定義條件變量,以及相關(guān)的`pthread_cond_wt`和`pthread_cond_signal`等函數(shù)來實現(xiàn)條件變量的使用。下面是一個簡單示例:
“`c
#include
#include
#include
pthread_cond_t cond;
pthread_mutex_t mutex;
int shared_data = 0;
void *worker_producer(void *arg) {
while (1) {
pthread_mutex_lock(&mutex);
shared_data += 1;
printf(“Produce %d\n”, shared_data);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
sleep(1);
}
return NULL;
}
void *worker_consumer(void *arg) {
while (1) {
pthread_mutex_lock(&mutex);
while (shared_data == 0) {
pthread_cond_wt(&cond, &mutex);
}
shared_data -= 1;
printf(“Consume %d\n”, shared_data);
pthread_mutex_unlock(&mutex);
sleep(1);
}
return NULL;
}
int mn(int argc, char *argv[]) {
pthread_t t_producer, t_consumer;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&t_producer, NULL, worker_producer, NULL);
pthread_create(&t_consumer, NULL, worker_consumer, NULL);
pthread_join(t_producer, NULL);
pthread_join(t_consumer, NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}
“`
在上面的示例中,定義了一個全局變量shared_data和一個互斥鎖mutex,并且定義了一個條件變量cond。在worker_producer函數(shù)中,不斷地對共享資源shared_data進(jìn)行更新,并且通過`pthread_cond_signal`來通知worker_consumer線程去執(zhí)行,并且最后調(diào)用`pthread_mutex_unlock`來釋放互斥鎖。在worker_consumer函數(shù)中,首先調(diào)用`pthread_mutex_lock`來申請互斥鎖,然后通過while循環(huán)來判斷共享資源是否滿足條件,如果滿足條件,則執(zhí)行相關(guān)的操作,如果不滿足條件,則調(diào)用`pthread_cond_wt`來暫停自己的運行,并且等待worker_producer線程來喚醒它。在mn函數(shù)中創(chuàng)建了兩個線程分別執(zhí)行worker_producer函數(shù)和worker_consumer函數(shù),并且在結(jié)束時進(jìn)行一些資源的銷毀和清理工作。
相關(guān)問題拓展閱讀:
- Linux信號量
Linux信號量
信號量是包含一個非負(fù)整數(shù)型的變量,并且?guī)в袃蓚€原子操作wait和signal。Wait還可以被稱為down、P或lock,signal還可以被稱為up、V、unlock或post。在UNIX的API中(POSIX標(biāo)準(zhǔn))用的是wait和post。
對于wait操作,如果信號量的非負(fù)整形變量S大于0,wait就將其減1,如果S等于0,wait就將調(diào)用線程阻塞;對于post操作,如果有線程在信號量上阻塞(此時S等于0),post就會解除對某個等待線程的阻塞,使其從wait中返回,如果沒有線程阻塞在信號量上,post就將S加1.
由此可見,S可以被理解為一種資源的數(shù)量,信號量即是通過控制這種資源的分配來實現(xiàn)互斥和同步的。如果把S設(shè)為1,那么信號量即可使多線程并發(fā)運行。另外,信號量不僅允許使用者申請和釋放資源,而且還允許使用者創(chuàng)豎嘩造資源,這就賦予了信號量實現(xiàn)同步的功能??梢娦盘柫康墓δ芤然コ饬控S富許多。
POSIX信號量是一個sem_t類型的變量,但POSIX有兩種信號量的實現(xiàn)機制:
無名信號量
和
命名信號量
。無名信號量只可以在共享內(nèi)存的情況下,比如實現(xiàn)進(jìn)程中各個線程之間的互斥和同步,因此無名信號量也被稱作基于內(nèi)存的信號量;命名信號量通常用于不共享內(nèi)存的情況下,比如進(jìn)程間通信。
同時,在創(chuàng)建信號量時,根據(jù)信號量取值的不同,POSIX信號量還可以分為:
下面是POSIX信號量函數(shù)接口:
信號量的函數(shù)都以sem_開頭,線程中使用的基本信號函數(shù)有4個,他們都聲明在頭文件semaphore.h中,該頭文件定義了用于信號量操作的sem_t類型:
【sem_init函數(shù)】:
該函數(shù)用于創(chuàng)猜型建信號量,原型如下:
該函數(shù)初始化由sem指向的余兆行信號對象,設(shè)置它的共享選項,并給它一個初始的整數(shù)值。pshared控制信號量的類型,如果其值為0,就表示信號量是當(dāng)前進(jìn)程的局部信號量,否則信號量就可以在多個進(jìn)程間共享,value為sem的初始值。
該函數(shù)調(diào)用成功返回0,失敗返回-1。
【sem_destroy函數(shù)】:
該函數(shù)用于對用完的信號量進(jìn)行清理,其原型如下:
成功返回0,失敗返回-1。
【sem_wait函數(shù)】:
該函數(shù)用于以原子操作的方式將信號量的值減1。原子操作就是,如果兩個線程企圖同時給一個信號量加1或減1,它們之間不會互相干擾。其原型如下:
sem指向的對象是sem_init調(diào)用初始化的信號量。調(diào)用成功返回0,失敗返回-1。
sem_trywait()則是sem_wait()的非阻塞版本,當(dāng)條件不滿足時(信號量為0時),該函數(shù)直接返回EAGAIN錯誤而不會阻塞等待。
sem_timedwait()功能與sem_wait()類似,只是在指定的abs_timeout時間內(nèi)等待,超過時間則直接返回ETIMEDOUT錯誤。
【sem_post函數(shù)】:
該函數(shù)用于以原子操作的方式將信號量的值加1,其原型如下:
與sem_wait一樣,sem指向的對象是由sem_init調(diào)用初始化的信號量。調(diào)用成功時返回0,失敗返回-1。
【sem_getvalue函數(shù)】:
該函數(shù)返回當(dāng)前信號量的值,通過restrict輸出參數(shù)返回。如果當(dāng)前信號量已經(jīng)上鎖(即同步對象不可用),那么返回值為0,或為負(fù)數(shù),其絕對值就是等待該信號量解鎖的線程數(shù)。
【實例1】:
【實例2】:
之所以稱為命名信號量,是因為它有一個名字、一個用戶ID、一個組ID和權(quán)限。這些是提供給不共享內(nèi)存的那些進(jìn)程使用命名信號量的接口。命名信號量的名字是一個遵守路徑名構(gòu)造規(guī)則的字符串。
【sem_open函數(shù)】:
該函數(shù)用于創(chuàng)建或打開一個命名信號量,其原型如下:
參數(shù)name是一個標(biāo)識信號量的字符串。參數(shù)oflag用來確定是創(chuàng)建信號量還是連接已有的信號量。
oflag的參數(shù)可以為0,O_CREAT或O_EXCL:如果為0,表示打開一個已存在的信號量;如果為O_CREAT,表示如果信號量不存在就創(chuàng)建一個信號量,如果存在則打開被返回,此時mode和value都需要指定;如果為O_CREAT|O_EXCL,表示如果信號量存在則返回錯誤。
mode參數(shù)用于創(chuàng)建信號量時指定信號量的權(quán)限位,和open函數(shù)一樣,包括:S_IRUSR、S_IWUSR、S_IRGRP、S_IWGRP、S_IROTH、S_IWOTH。
value表示創(chuàng)建信號量時,信號量的初始值。
【sem_close函數(shù)】:
該函數(shù)用于關(guān)閉命名信號量:
單個程序可以用sem_close函數(shù)關(guān)閉命名信號量,但是這樣做并不能將信號量從系統(tǒng)中刪除,因為命名信號量在單個程序執(zhí)行之外是具有持久性的。當(dāng)進(jìn)程調(diào)用_exit、exit、exec或從main返回時,進(jìn)程打開的命名信號量同樣會被關(guān)閉。
【sem_unlink函數(shù)】:
sem_unlink函數(shù)用于在所有進(jìn)程關(guān)閉了命名信號量之后,將信號量從系統(tǒng)中刪除:
【信號量操作函數(shù)】:
與無名信號量一樣,操作信號量的函數(shù)如下:
命名信號量是隨內(nèi)核持續(xù)的。當(dāng)命名信號量創(chuàng)建后,即使當(dāng)前沒有進(jìn)程打開某個信號量,它的值依然保持,直到內(nèi)核重新自舉或調(diào)用sem_unlink()刪除該信號量。
無名信號量的持續(xù)性要根據(jù)信號量在內(nèi)存中的位置確定:
很多時候信號量、互斥量和條件變量都可以在某種應(yīng)用中使用,那這三者的差異有哪些呢?下面列出了這三者之間的差異:
關(guān)于linux 線程同步互斥的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
創(chuàng)新互聯(lián)服務(wù)器托管擁有成都T3+級標(biāo)準(zhǔn)機房資源,具備完善的安防設(shè)施、三線及BGP網(wǎng)絡(luò)接入帶寬達(dá)10T,機柜接入千兆交換機,能夠有效保證服務(wù)器托管業(yè)務(wù)安全、可靠、穩(wěn)定、高效運行;創(chuàng)新互聯(lián)專注于成都服務(wù)器托管租用十余年,得到成都等地區(qū)行業(yè)客戶的一致認(rèn)可。
文章標(biāo)題:Linux下實現(xiàn)線程同步互斥的方法(linux線程同步互斥)
當(dāng)前地址:http://m.5511xx.com/article/dphigsh.html


咨詢
建站咨詢
