在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

詳細(xì)談?wù)凩inux中的多線程同步和互斥機(jī)制

dyquk4xk2p3d ? 來(lái)源:Linux兵工廠 ? 作者:Linux兵工廠 ? 2023-03-20 09:09 ? 次閱讀

同步和互斥

互斥:多線程中互斥是指多個(gè)線程訪問(wèn)同一資源時(shí)同時(shí)只允許一個(gè)線程對(duì)其進(jìn)行訪問(wèn),具有唯一性和排它性。但互斥無(wú)法限制訪問(wèn)者對(duì)資源的訪問(wèn)順序,即訪問(wèn)是無(wú)序的;

同步:多線程同步是指在互斥的基礎(chǔ)上(大多數(shù)情況),通過(guò)其它機(jī)制實(shí)現(xiàn)訪問(wèn)者對(duì)資源的有序訪問(wèn)。在大多數(shù)情況下,同步已經(jīng)實(shí)現(xiàn)了互斥,特別是所有寫(xiě)入資源的情況必定是互斥的。少數(shù)情況是指可以允許多個(gè)訪問(wèn)者同時(shí)訪問(wèn)資源。

互斥鎖

在多任務(wù)操作系統(tǒng)中,同時(shí)運(yùn)行的多個(gè)任務(wù)可能都需要使用同一種資源。為了同一時(shí)刻只允許一個(gè)任務(wù)訪問(wèn)資源,需要用互斥鎖對(duì)資源進(jìn)行保護(hù)?;コ怄i是一種簡(jiǎn)單的加鎖的方法來(lái)控制對(duì)共享資源的訪問(wèn),互斥鎖只有兩種狀態(tài),即上鎖( lock )和解鎖( unlock )。

互斥鎖操作基本流程

訪問(wèn)共享資源前,對(duì)互斥鎖進(jìn)行加鎖

完成加鎖后訪問(wèn)共享資源

對(duì)共享資源完成訪問(wèn)后,對(duì)互斥鎖進(jìn)行解鎖

對(duì)互斥鎖進(jìn)行加鎖后,任何其他試圖再次對(duì)互斥鎖加鎖的線程將會(huì)被阻塞,直到鎖被釋放

互斥鎖特性

原子性:互斥鎖是一個(gè)原子操作,操作系統(tǒng)保證如果一個(gè)線程鎖定了一個(gè)互斥鎖,那么其他線程在同一時(shí)間不會(huì)成功鎖定這個(gè)互斥鎖

唯一性:如果一個(gè)線程鎖定了一個(gè)互斥鎖,在它解除鎖之前,其他線程不可以鎖定這個(gè)互斥鎖

非忙等待:如果一個(gè)線程已經(jīng)鎖定了一個(gè)互斥鎖,第二個(gè)線程又試圖去鎖定這個(gè)互斥鎖,則第二個(gè)線程將被掛起且不占用任何CPU資源,直到第一個(gè)線程解除對(duì)這個(gè)互斥鎖的鎖定為止,第二個(gè)線程則被喚醒并繼續(xù)執(zhí)行,同時(shí)鎖定這個(gè)互斥鎖

示例

#include
#include
#include
#include
#include

char*pTestBuf=nullptr;//全局變量

/*定義互斥鎖*/
pthread_mutex_tmutex;

void*ThrTestMutex(void*p)
{
pthread_mutex_lock(&mutex);//加鎖
{
pTestBuf=(char*)p;
sleep(1);
}
pthread_mutex_unlock(&mutex);//解鎖
}

intmain()
{
/*初始化互斥量,默認(rèn)屬性*/
pthread_mutex_init(&mutex,NULL);

/*創(chuàng)建兩個(gè)線程對(duì)共享資源訪問(wèn)*/
pthread_ttid1,tid2;
pthread_create(&tid1,NULL,ThrTestMutex,(void*)"Thread1");
pthread_create(&tid2,NULL,ThrTestMutex,(void*)"Thread2");

/*等待線程結(jié)束*/
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);

/*銷(xiāo)毀互斥鎖*/
pthread_mutex_destroy(&mutex);

return0;
}

讀寫(xiě)鎖

讀寫(xiě)鎖允許更高的并行性,也叫共享互斥鎖。互斥量要么是加鎖狀態(tài),要么就是解鎖狀態(tài),而且一次只有一個(gè)線程可以對(duì)其加鎖。讀寫(xiě)鎖可以有3種狀態(tài):讀模式下加鎖狀態(tài)、寫(xiě)模式加鎖狀態(tài)、不加鎖狀態(tài)。一次只有一個(gè)線程可以占有寫(xiě)模式的讀寫(xiě)鎖,但是多個(gè)線程可以同時(shí)占有讀模式的讀寫(xiě)鎖,即允許多個(gè)線程讀但只允許一個(gè)線程寫(xiě)。

當(dāng)讀操作較多,寫(xiě)操作較少時(shí),可用讀寫(xiě)鎖提高線程讀并發(fā)性

讀寫(xiě)鎖特性

如果有線程讀數(shù)據(jù),則允許其它線程執(zhí)行讀操作,但不允許寫(xiě)操作

如果有線程寫(xiě)數(shù)據(jù),則其它線程都不允許讀、寫(xiě)操作

如果某線程申請(qǐng)了讀鎖,其它線程可以再申請(qǐng)讀鎖,但不能申請(qǐng)寫(xiě)鎖

如果某線程申請(qǐng)了寫(xiě)鎖,其它線程不能申請(qǐng)讀鎖,也不能申請(qǐng)寫(xiě)鎖

讀寫(xiě)鎖適合于對(duì)數(shù)據(jù)的讀次數(shù)比寫(xiě)次數(shù)多得多的情況

讀寫(xiě)鎖創(chuàng)建和銷(xiāo)毀

#include
intphtread_rwlock_init(pthread_rwlock_t*restrictrwlock,constpthread_rwlockattr_t*restrictattr);
intpthread_rwlock_destroy(pthread_rwlock_t*rwlock);

參數(shù):rwlock:讀寫(xiě)鎖,attr:讀寫(xiě)鎖屬性

返回值:成功返回0,出錯(cuò)返回錯(cuò)誤碼

讀寫(xiě)鎖加鎖解鎖

#include
/**加讀鎖*/
intpthread_rwlock_rdlock(pthread_rwlock_t*rwlock);
/**加寫(xiě)鎖*/
intpthread_rwlock_wrlock(pthread_rwlock_t*rwlock);
/**釋放鎖*/
intpthread_rwlock_unlock(pthread_rwlock_t*rwlock);

參數(shù):rwlock:讀寫(xiě)鎖

返回值:成功返回 0;出錯(cuò),返回錯(cuò)誤碼

示例

#include
#include
#include
#include
#include

/*定義讀寫(xiě)鎖*/
pthread_rwlock_trwlock;

/*定義共享資源變量*/
intg_nNum=0;

/*讀操作其他線程允許讀操作不允許寫(xiě)操作*/
void*fun1(void*arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock);
{
printf("readthread1==%d
",g_nNum);
}
pthread_rwlock_unlock(&rwlock);

sleep(1);
}
}

/*讀操作,其他線程允許讀操作,不允許寫(xiě)操作*/
void*fun2(void*arg)
{
while(1)
{
pthread_rwlock_rdlock(&rwlock);
{
printf("readthread2==%d
",g_nNum);
}
pthread_rwlock_unlock(&rwlock);

sleep(1);
}
}

/*寫(xiě)操作,其它線程都不允許讀或?qū)懖僮?/
void*fun3(void*arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
{
g_nNum++;
printf("writethread1
");
}
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
/*寫(xiě)操作,其它線程都不允許讀或?qū)懖僮?/
void*fun4(void*arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
{
g_nNum++;
printf("writethread2
");
}
pthread_rwlock_unlock(&rwlock);

sleep(1);
}
}

intmain(intarc,char*argv[])
{
pthread_tThrId1,ThrId2,ThrId3,ThrId4;

pthread_rwlock_init(&rwlock,NULL);//初始化一個(gè)讀寫(xiě)鎖

/*創(chuàng)建測(cè)試線程*/
pthread_create(&ThrId1,NULL,fun1,NULL);
pthread_create(&ThrId2,NULL,fun2,NULL);
pthread_create(&ThrId3,NULL,fun3,NULL);
pthread_create(&ThrId4,NULL,fun4,NULL);

/*等待線程結(jié)束,回收其資源*/
pthread_join(ThrId1,NULL);
pthread_join(ThrId2,NULL);
pthread_join(ThrId3,NULL);
pthread_join(ThrId4,NULL);

pthread_rwlock_destroy(&rwlock);//銷(xiāo)毀讀寫(xiě)鎖

return0;
}

結(jié)果

be5272ee-c6aa-11ed-bfe3-dac502259ad0.png

自旋鎖

自旋鎖與互斥鎖功能相同,唯一不同的就是互斥鎖阻塞后休眠不占用CPU,而自旋鎖阻塞后不會(huì)讓出CPU,會(huì)一直忙等待,直到得到鎖

自旋鎖在用戶態(tài)較少用,而在內(nèi)核態(tài)使用的比較多

自旋鎖的使用場(chǎng)景:鎖的持有時(shí)間比較短,或者說(shuō)小于2次上下文切換的時(shí)間

自旋鎖在用戶態(tài)的函數(shù)接口和互斥量一樣,把pthread_mutex_lock()/pthread_mutex_unlock()中mutex換成spin,如:pthread_spin_init()

自旋鎖函數(shù)

linux中的自旋鎖用結(jié)構(gòu)體spinlock_t 表示,定義在include/linux/spinlock_type.h。自旋鎖的接口函數(shù)全部定義在include/linux/spinlock.h頭文件中,實(shí)際使用時(shí)只需include即可

示例

include
spinlock_tlock;//定義自旋鎖
spin_lock_init(&lock);//初始化自旋鎖
spin_lock(&lock);//獲得鎖,如果沒(méi)獲得成功則一直等待
{
.......//處理臨界資源
}
spin_unlock(&lock);//釋放自旋鎖

條件變量

條件變量用來(lái)阻塞一個(gè)線程,直到條件發(fā)生。通常條件變量和互斥鎖同時(shí)使用。條件變量使線程可以睡眠等待某種條件滿足。條件變量是利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制。

條件變量的邏輯:一個(gè)線程掛起去等待條件變量的條件成立,而另一個(gè)線程使條件成立。

基本原理

線程在改變條件狀態(tài)之前先鎖住互斥量。如果條件為假,線程自動(dòng)阻塞,并釋放等待狀態(tài)改變的互斥鎖。如果另一個(gè)線程改變了條件,它發(fā)信號(hào)給關(guān)聯(lián)的條件變量,喚醒一個(gè)或多個(gè)等待它的線程。如果兩進(jìn)程共享可讀寫(xiě)的內(nèi)存,條件變量可以被用來(lái)實(shí)現(xiàn)這兩進(jìn)程間的線程同步

示例

#include
#include
#include
#include

pthread_cond_ttaxicond=PTHREAD_COND_INITIALIZER;
pthread_mutex_ttaximutex=PTHREAD_MUTEX_INITIALIZER;

void*ThrFun1(void*name)
{
char*p=(char*)name;

//加鎖,把信號(hào)量加入隊(duì)列,釋放信號(hào)量
pthread_mutex_lock(&taximutex);
{
pthread_cond_wait(&taxicond,&taximutex);
}
pthread_mutex_unlock(&taximutex);

printf("ThrFun1:%snowgotasignal!
",p);
pthread_exit(NULL);
}

void*ThrFun2(void*name)
{
char*p=(char*)name;
printf("ThrFun2:%scondsignal.
",p);//發(fā)信號(hào)
pthread_cond_signal(&taxicond);
pthread_exit(NULL);
}

intmain(intargc,char**argv)
{
pthread_tThread1,Thread2;
pthread_attr_tthreadattr;
pthread_attr_init(&threadattr);//線程屬性初始化

//創(chuàng)建三個(gè)線程
pthread_create(&Thread1,&threadattr,ThrFun1,(void*)"Thread1");
sleep(1);

pthread_create(&Thread2,&threadattr,ThrFun2,(void*)"Thread2");
sleep(1);

pthread_join(Thread1,NULL);
pthread_join(Thread2,NULL);

return0;
}

結(jié)果

be6a4fd6-c6aa-11ed-bfe3-dac502259ad0.png

虛假喚醒

當(dāng)線程從等待已發(fā)出信號(hào)的條件變量中醒來(lái),卻發(fā)現(xiàn)它等待的條件不滿足時(shí),就會(huì)發(fā)生虛假喚醒。之所以稱為虛假,是因?yàn)樵摼€程似乎無(wú)緣無(wú)故地被喚醒了。但是虛假喚醒不會(huì)無(wú)緣無(wú)故發(fā)生:它們通常是因?yàn)樵诎l(fā)出條件變量信號(hào)和等待線程最終運(yùn)行之間,另一個(gè)線程運(yùn)行并更改了條件

避免虛假喚醒

在wait端,我們必須把判斷條件和wait()放到while循環(huán)中

pthread_mutex_lock(&taximutex);
{
while(value!=wantValue)
{
pthread_cond_wait(&taxicond,&taximutex);
}
}
pthread_mutex_unlock(&taximutex);

信號(hào)量

信號(hào)量用于進(jìn)程或線程間的同步和互斥,信號(hào)量本質(zhì)上是一個(gè)非負(fù)的整數(shù)計(jì)數(shù)器,它被用來(lái)控制對(duì)公共資源的訪問(wèn)。編程時(shí)可根據(jù)操作信號(hào)量值的結(jié)果判斷是否對(duì)公共資源具有訪問(wèn)的權(quán)限,當(dāng)信號(hào)量值大于0時(shí),則可以訪問(wèn),否則將阻塞

#include

//初始化信號(hào)量
intsem_init(sem_t*sem,intpshared,unsignedintvalue);

//信號(hào)量P操作(減1)
intsem_wait(sem_t*sem);

//以非阻塞的方式來(lái)對(duì)信號(hào)量進(jìn)行減1操作
intsem_trywait(sem_t*sem);

//信號(hào)量V操作(加1)
intsem_post(sem_t*sem);

//獲取信號(hào)量的值
intsem_getvalue(sem_t*sem,int*sval);

//銷(xiāo)毀信號(hào)量
intsem_destroy(sem_t*sem);

示例

//信號(hào)量用于同步實(shí)例
#include
#include
#include
#include

sem_tsem_g,sem_p;//定義兩個(gè)信號(hào)量
chars8Test='a';

void*pthread_g(void*arg)//此線程改變字符的值
{
while(1)
{
sem_wait(&sem_g);
s8Test++;
sleep(2);
sem_post(&sem_p);
}
}
void*pthread_p(void*arg)//此線程打印字符的值
{
while(1)
{
sem_wait(&sem_p);
printf("%c",s8Test);
fflush(stdout);
sem_post(&sem_g);
}
}
intmain(intargc,char*argv[])
{
pthread_ttid1,tid2;
sem_init(&sem_g,0,0);//初始化信號(hào)量為0
sem_init(&sem_p,0,1);//初始化信號(hào)量為1

pthread_create(&tid1,NULL,pthread_g,NULL);
pthread_create(&tid2,NULL,pthread_p,NULL);

pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return0;
}

結(jié)果

be7776e8-c6aa-11ed-bfe3-dac502259ad0.png



審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10863

    瀏覽量

    211782
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11304

    瀏覽量

    209524
  • 計(jì)數(shù)器
    +關(guān)注

    關(guān)注

    32

    文章

    2256

    瀏覽量

    94575
  • 信號(hào)量
    +關(guān)注

    關(guān)注

    0

    文章

    53

    瀏覽量

    8344
  • Linux編程
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

    618

原文標(biāo)題:詳解Linux多線程中互斥鎖、讀寫(xiě)鎖、自旋鎖、條件變量、信號(hào)量

文章出處:【微信號(hào):良許Linux,微信公眾號(hào):良許Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux多線程機(jī)制

    另一個(gè)帶類型的指針變量線程同步互斥同步(按照預(yù)想的順序執(zhí)行)M->Y->M->Y->M->YM->YYY->M->YYY......互斥
    發(fā)表于 11-11 09:53

    Linux多線程機(jī)制

    定義變量,但不可以使用(*p = 100, p++, p--)  ///無(wú)類型指針只能賦值給另一個(gè)帶類型的指針變量  線程同步互斥  同步(按照預(yù)想的順序執(zhí)行)  M->Y->M-
    發(fā)表于 01-10 14:59

    Linux多線程線程同步

    。同一進(jìn)程內(nèi)的線程共享進(jìn)程的地址空間。通信:進(jìn)程間通信IPC,線程間可以直接讀寫(xiě)進(jìn)程數(shù)據(jù)段(如全局變量)來(lái)進(jìn)行通信——需要進(jìn)程同步互斥手段的輔助,以保證數(shù)據(jù)的一致性。調(diào)度和切換:
    發(fā)表于 12-08 14:14

    多線程同步互斥有幾種實(shí)現(xiàn)方法

    線程同步是指線程之間所具有的一種制約關(guān)系,一個(gè)線程的執(zhí)行依賴另一個(gè)線程的消息,當(dāng)它沒(méi)有得到另一個(gè)線程
    發(fā)表于 08-05 06:06

    Win32多線程同步技術(shù)淺析

    簡(jiǎn)要介紹了在Win32環(huán)境下多線程訪問(wèn)共享資源時(shí)的同步機(jī)制,討論了主要的4種同步對(duì)象(臨界區(qū)、互斥元、事件、信號(hào)量),并描述了它們的優(yōu)缺點(diǎn),給出了使用Win32 API函數(shù)操控這4種對(duì)
    發(fā)表于 11-14 10:55 ?31次下載
    Win32<b class='flag-5'>多線程</b><b class='flag-5'>同步</b>技術(shù)淺析

    多線程與聊天室程序的創(chuàng)建

    多線程程序的編寫(xiě),多線程應(yīng)用容易出現(xiàn)的問(wèn)題。互斥對(duì)象的講解,如何采用互斥對(duì)象來(lái)實(shí)現(xiàn)多線程
    發(fā)表于 05-16 15:22 ?0次下載

    了解Linux多線程線程同步

    進(jìn)程間通信IPC,線程間可以直接讀寫(xiě)進(jìn)程數(shù)據(jù)段(如全局變量)來(lái)進(jìn)行通信——需要進(jìn)程同步互斥手段的輔助,以保證數(shù)據(jù)的一致性。
    發(fā)表于 04-23 14:23 ?727次閱讀
    了解<b class='flag-5'>Linux</b><b class='flag-5'>多線程</b>及<b class='flag-5'>線程</b>間<b class='flag-5'>同步</b>

    linux多線程機(jī)制-線程同步

    ,而且可以在不同應(yīng)用程序的線程之間實(shí)現(xiàn)對(duì)資源的安全共享。Linux通過(guò)pthread_mutex_t來(lái)定義互斥機(jī)制完成
    發(fā)表于 04-02 14:42 ?465次閱讀

    Linux多線程同步互斥量Mutex詳解

    嵌入式linux中文站向各位愛(ài)好者介紹linux常見(jiàn)同步方式互斥量Mutex的使用方法1. 初始化:在Linux下,
    發(fā)表于 04-02 14:45 ?303次閱讀

    Linux 多線程互斥互斥

    同步同一個(gè)進(jìn)程的多個(gè)線程共享所在進(jìn)程的內(nèi)存資源,當(dāng)多個(gè)線程在同一時(shí)刻同時(shí)訪問(wèn)同一種共享資源時(shí),需要相互協(xié)調(diào),以避免出現(xiàn)數(shù)據(jù)的不一致和覆蓋等問(wèn)題,
    發(fā)表于 04-02 14:47 ?271次閱讀

    Linux多線程同步

    操作。?多線程同步對(duì)于多線程程序來(lái)說(shuō),同步(synchronization)是指在一定的時(shí)間內(nèi)只允許某一個(gè)
    發(fā)表于 04-02 14:47 ?418次閱讀

    三種Linux的常用多線程同步方式淺析

    嵌入式linux中文站給大家介紹三種Linux的常用多線程同步方式:互斥量,條件變量,信號(hào)量。
    發(fā)表于 05-02 14:49 ?3081次閱讀
    三種<b class='flag-5'>Linux</b><b class='flag-5'>中</b>的常用<b class='flag-5'>多線程</b><b class='flag-5'>同步</b>方式淺析

    Linux多線程編程的知識(shí)點(diǎn)

    Hello、Hello大家好,我是木榮,今天我們繼續(xù)來(lái)聊一聊Linux多線程編程的重要知識(shí)點(diǎn),詳細(xì)談?wù)?/b>
    發(fā)表于 04-26 17:27 ?603次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>中</b><b class='flag-5'>多線程</b>編程的知識(shí)點(diǎn)

    多線程同步的幾種方法

    多線程同步是指在多個(gè)線程并發(fā)執(zhí)行的情況下,為了保證線程執(zhí)行的正確性和一致性,需要采用特定的方法來(lái)協(xié)調(diào)線程之間的執(zhí)行順序和共享資源的訪問(wèn)。下面
    的頭像 發(fā)表于 11-17 14:16 ?1187次閱讀

    多線程如何保證數(shù)據(jù)的同步

    。本文將詳細(xì)介紹多線程數(shù)據(jù)同步的概念、問(wèn)題、以及常見(jiàn)的解決方案。 一、多線程數(shù)據(jù)同步概念 在多線程
    的頭像 發(fā)表于 11-17 14:22 ?1237次閱讀
    主站蜘蛛池模板: 男人的天堂在线精品视频| 国产在线精品美女观看| www.色日本| 成人午夜免费剧场| 一色桃子juy774在线播放| 欧美大片xxxxbbbb| 天天做天天爱天天影视综合| 男人和女人在床做黄的网站| 特级黄视频| 最近视频在线播放免费观看 | 亚洲国产毛片aaaaa无费看| 色系视频在线观看免费观看| 成 人 免 费 黄 色| 2019天天操夜夜操| 色综合天天综合网国产国产人| free性欧美video| 91国内在线视频| 日本免费色视频| 特黄一级| 在线种子资源网| 丁香月婷婷| 4438x全国免费| 男女爱爱福利| 国产午夜精品理论片在线 | 婷婷九月丁香| 1024成人| 男女交性视频免费视频| 美日韩免费视频| 国产精品1区2区3区在线播放| 五月婷婷 六月丁香| 最近高清免费观看视频大全 | 开心六月婷婷| 国产成人在线影院| 色批| 人人艹人人艹| 五月婷婷六月爱| 亚洲精品mv在线观看| 国内视频一区二区| 波多野结衣在线视频观看| 亚洲一区有码| 狠狠狠色丁香婷婷综合久久五月 |