校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > 超詳細講解Linux C++多線程同步的方式

超詳細講解Linux C++多線程同步的方式

熱門標簽:烏海智能電話機器人 貴陽教育行業電話外呼系統 400電話申請方案 撫順移動400電話申請 寧夏房產智能外呼系統要多少錢 做外呼系統的公司違法嗎 在百度地圖標注車輛 藍點外呼系統 威海人工外呼系統供應商

背景問題:在特定的應用場景下,多線程不進行同步會造成什么問題?

通過多線程模擬多窗口售票為例:

#include <iostream>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

using namespace std;

int ticket_sum=20;
void *sell_ticket(void *arg)
{
    for(int i=0; i<20; i++)
    {
        if(ticket_sum>0)
        {
            sleep(1);
            cout<<"sell the "<<20-ticket_sum+1<<"th"<<endl;
            ticket_sum--;
        }
    }
    return 0;
}

int main()
{
    int flag;
    pthread_t tids[4];

    for(int i=0; i<4; i++)
    {
        flag=pthread_create(&tids[i],NULL,&sell_ticket,NULL);
        if(flag)
        {
            cout<<"pthread create error ,flag="<<flag<<endl;
            return flag;
        }
    }

    sleep(20);
    void *ans;
    for(int i=0; i<4; i++)
    {
        flag=pthread_join(tids[i],&ans);
        if(flag)
        {
            cout<<"tid="<<tids[i]<<"join erro flag="<<flag<<endl;
            return flag;
        }
        cout<<"ans="<<ans<<endl;
    }
    return 0;
}

分析:總票數只有20張,卻賣出了23張,是非常明顯的超買超賣問題,而造成這個問題的根本原因就是同時發生的各個線程都可以對ticket_sum進行讀取和寫入!

ps:

       1.在并發情況下,指令執行的先后順序由內核決定,同一個線程內部,指令按照先后順序執行,但不同線程之間的指令很難說清楚是哪一個先執行,如果運行的結果依賴于不同線程執行的先后的話,那么就會形成競爭條件,在這樣的情況下,計算的結果很難預知,所以應該盡量避免競爭條件的形成

       2.最常見的解決競爭條件的方法是將原先分離的兩個指令構成一個不可分割的原子操作,而其他任務不能插入到原子操作中!

       3.對多線程來說,同步指的是在一定時間內只允許某一個線程訪問某個資源,而在此時間內,不允許其他線程訪問該資源!

       4.線程同步的常見方法:互斥鎖,條件變量,讀寫鎖,信號量

一.互斥鎖

本質就是一個特殊的全局變量,擁有lock和unlock兩種狀態,unlock的互斥鎖可以由某個線程獲得,一旦獲得,這個互斥鎖會鎖上變成lock狀態,此后只有該線程由權力打開該鎖,其他線程想要獲得互斥鎖,必須得到互斥鎖再次被打開之后

采用互斥鎖來同步資源:

#include <iostream>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

using namespace std;

int ticket_sum=20;
pthread_mutex_t mutex_x=PTHREAD_MUTEX_INITIALIZER;//static init mutex

void *sell_ticket(void *arg)
{
    for(int i=0; i<20; i++)
    {
        pthread_mutex_lock(&mutex_x);//atomic opreation through mutex lock
        if(ticket_sum>0)
        {
            sleep(1);
            cout<<"sell the "<<20-ticket_sum+1<<"th"<<endl;
            ticket_sum--;
        }
        pthread_mutex_unlock(&mutex_x);
    }
    return 0;
}

int main()
{
    int flag;
    pthread_t tids[4];

    for(int i=0; i<4; i++)
    {
        flag=pthread_create(&tids[i],NULL,&sell_ticket,NULL);
        if(flag)
        {
            cout<<"pthread create error ,flag="<<flag<<endl;
            return flag;
        }
    }

    sleep(20);
    void *ans;
    for(int i=0; i<4; i++)
    {
        flag=pthread_join(tids[i],&ans);
        if(flag)
        {
            cout<<"tid="<<tids[i]<<"join erro flag="<<flag<<endl;
            return flag;
        }
        cout<<"ans="<<ans<<endl;
    }
    return 0;
}

分析:通過為售票的核心代碼段加互斥鎖使得其變成了一個原子性操作!不會被其他線程影響

1.互斥鎖的初始化

互斥鎖的初始化分為靜態初始化和動態初始化

靜態:pthread_mutex_t mutex_x=PTHREAD_MUTEX_INITIALIZER;//static init mutex

動態:pthread_mutex_init函數

ps:互斥鎖靜態初始化和動態初始化的區別?

待補充。。。。

2.互斥鎖的相關屬性及分類

//初始化互斥鎖屬性
pthread_mutexattr_init(pthread_mutexattr_t attr);

//銷毀互斥鎖屬性
pthread_mutexattr_destroy(pthread_mutexattr_t attr);

//用于獲取互斥鎖屬性
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr , int *restrict pshared);

//用于設置互斥鎖屬性
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr , int pshared);

attr表示互斥鎖的屬性

pshared表示互斥鎖的共享屬性,由兩種取值:

1)PTHREAD_PROCESS_PRIVATE:鎖只能用于一個進程內部的兩個線程進行互斥(默認情況)

2)PTHREAD_PROCESS_SHARED:鎖可用于兩個不同進程中的線程進行互斥,使用時還需要在進程共享內存中分配互斥鎖,然后為該互斥鎖指定屬性就可以了

互斥鎖的分類:

//獲取互斥鎖類型
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr , int *restrict type);

//設置互斥鎖類型
int pthread_mutexattr_settype(const pthread_mutexattr_t *restrict attr , int type);

參數type表示互斥鎖的類型,總共有以下四種類型:

1.PTHREAD_MUTEX_NOMAL:標準互斥鎖,第一次上鎖成功,第二次上鎖會失敗并阻塞

2.PTHREAD_MUTEX_RECURSIVE:遞歸互斥鎖,第一次上鎖成功,第二次上鎖還是會成功,可以理解為內部有一個計數器,每加一次鎖計數器加1,解鎖減1

3.PTHREAD_MUTEX_ERRORCHECK:檢查互斥鎖,第一次上鎖會成功,第二次上鎖出錯返回錯誤信息,不會阻塞

4.PTHREAD_MUTEX_DEFAULT:默認互斥鎖,第一次上鎖會成功,第二次上鎖會失敗

3.測試加鎖函數

int pthread_mutex_lock(&mutex):測試加鎖函數在鎖已經被占據時返回EBUSY而不是掛起等待,當然,如果鎖沒有被占領的話可以獲得鎖

為了清楚的看到兩個線程爭用資源的情況,我們使得其中一個函數使用測試加鎖函數進行加鎖,而另外一個使用正常的加鎖函數進行加鎖

#include <iostream>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
using namespace std;

int ticket_sum=20;
pthread_mutex_t mutex_x=PTHREAD_MUTEX_INITIALIZER;//static init mutex

void *sell_ticket_1(void *arg)
{
    for(int i=0; i<20; i++)
    {
        pthread_mutex_lock(&mutex_x);
        if(ticket_sum>0)
        {
            sleep(1);
            cout<<"thread_1 sell the "<<20-ticket_sum+1<<"th ticket"<<endl;
            ticket_sum--;
        }
        sleep(1);
        pthread_mutex_unlock(&mutex_x);
        sleep(1);
    }
    return 0;
}

void *sell_ticket_2(void *arg)
{
    int flag;
    for(int i=0; i<10; i++)
    {
        flag=pthread_mutex_trylock(&mutex_x);
        if(flag==EBUSY)
        {
            cout<<"sell_ticket_2:the variable is locked by sell_ticket_1"<<endl;
        }
        else if(flag==0)
        {
            if(ticket_sum>0)
            {
                sleep(1);
                cout<<"thread_2 sell the "<<20-ticket_sum+1<<"th tickets"<<endl;
                ticket_sum--;
            }
            pthread_mutex_unlock(&mutex_x);
        }
        sleep(1);
    }
    return 0;
}
int main()
{
    int flag;
    pthread_t tids[2];

    flag=pthread_create(&tids[0],NULL,&sell_ticket_1,NULL);
    if(flag)
    {
        cout<<"pthread create error ,flag="<<flag<<endl;
        return flag;
    }

    flag=pthread_create(&tids[1],NULL,&sell_ticket_2,NULL);
    if(flag)
    {
        cout<<"pthread create error ,flag="<<flag<<endl;

        return flag;
    }

    void *ans;
    sleep(30);
    flag=pthread_join(tids[0],&ans);
    if(flag)
    {
        cout<<"tid="<<tids[0]<<"join erro flag="<<flag<<endl;
        return flag;
    }
    else
    {
        cout<<"ans="<<ans<<endl;
    }

    flag=pthread_join(tids[1],&ans);
    if(flag)
    {
        cout<<"tid="<<tids[1]<<"join erro flag="<<flag<<endl;
        return flag;
    }
    else
    {
        cout<<"ans="<<ans<<endl;
    }

    return 0;
}

分析:通過測試加鎖函數我們可以清晰的看到兩個線程爭用資源的情況

二.條件變量

互斥量不是萬能的,比如某個線程正在等待共享數據內某個條件出現,可可能需要重復對數據對象加鎖和解鎖(輪詢),但是這樣輪詢非常耗費時間和資源,而且效率非常低,所以互斥鎖不太適合這種情況

我們需要這樣一種方法:當線程在等待滿足某些條件時使線程進入睡眠狀態,一旦條件滿足,就換線因等待滿足特定條件而睡眠的線程

如果我們能夠實現這樣一種方法,程序的效率無疑會大大提高,而這種方法正是條件變量!

樣例:

#include <iostream>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
using namespace std;

pthread_cond_t qready=PTHREAD_COND_INITIALIZER;   //cond
pthread_mutex_t qlock=PTHREAD_MUTEX_INITIALIZER;  //mutex

int x=10,y=20;

void *f1(void *arg)
{
  cout<<"f1 start"<<endl;
  pthread_mutex_lock(&qlock);
  while(x<y)
  {
    pthread_cond_wait(&qready,&qlock);
  }
  pthread_mutex_unlock(&qlock);
  sleep(3);
  cout<<"f1 end"<<endl;
  return 0;
}

void *f2(void *arg)
{
  cout<<"f2 start"<<endl;
  pthread_mutex_lock(&qlock);
  x=20;
  y=10;
  cout<<"has a change,x="<<x<<" y="<<y<<endl;
  pthread_mutex_unlock(&qlock);
  if(x>y)
  {
    pthread_cond_signal(&qready);
  }
  cout<<"f2 end"<<endl;
  return 0;
}

int main()
{
  pthread_t tids[2];
  int flag;

  flag=pthread_create(&tids[0],NULL,f1,NULL);
  if(flag)
  {
    cout<<"pthread 1 create error "<<endl;
    return flag;
  }

  sleep(2);

  flag=pthread_create(&tids[1],NULL,f2,NULL);
  if(flag)
  {
    cout<<"pthread 2 create erro "<<endl;
    return flag;
  }

  sleep(5);
  return 0;
}

分析:線程1不滿足條件被阻塞,然后線程2運行,改變了條件,線程2發行條件改變了通知線程1運行,然后線程2結束,然后線程1繼續運行,然后線程1結束,為了確保線程1先執行,在創建線程2之前我們sleep了2秒

ps:

1.條件變量通過運行線程阻塞和等待另一個線程發送信號的方法彌補互斥鎖的不足,常常和互斥鎖一起使用,使用時,條件變量被用來阻塞一個線程,當條件不滿足時,線程往往解開響應的互斥鎖并等待條件發生變化,一旦其他的某個線程改變了條件變量,它將通知響應的條件變量換線一個或多個正被此條件變量阻塞的線程,這些線程將重新鎖定互斥鎖并且重新測試條件是否滿足

1.條件變量的相關函數

1)創建

靜態方式:pthread_cond_t cond PTHREAD_COND_INITIALIZER

動態方式:int pthread_cond_init(&cond,NULL)

Linux thread 實現的條件變量不支持屬性,所以NULL(cond_attr參數)

2)注銷

int pthread_cond_destory(&cond)

只有沒有線程在該條件變量上,該條件變量才能注銷,否則返回EBUSY

因為Linux實現的條件變量沒有分配什么資源,所以注銷動作只包括檢查是否有等待線程!(請參考條件變量的底層實現)

3)等待

條件等待:int pthread_cond_wait(&cond,&mutex)

計時等待:int pthread_cond_timewait(&cond,&mutex,time)

1.其中計時等待如果在給定時刻前條件沒有被滿足,則返回ETIMEOUT,結束等待

2.無論那種等待方式,都必須有一個互斥鎖配合,以防止多個線程同時請求pthread_cond_wait形成競爭條件!

3.在調用pthread_cond_wait前必須由本線程加鎖

4)激發

激發一個等待線程:pthread_cond_signal(&cond)

激發所有等待線程:pthread_cond_broadcast(&cond)

重要的是,pthread_cond_signal不會存在驚群效應,也就是是它最多給一個等待線程發信號,不會給所有線程發信號喚醒提他們,然后要求他們自己去爭搶資源!

pthread_cond_signal會根據等待線程的優先級和等待時間來確定激發哪一個等待線程

下面看一個程序,找到程序存在的問題

#include <iostream>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
using namespace std;

pthread_cond_t taxi_cond=PTHREAD_COND_INITIALIZER; //taix arrive cond
pthread_mutex_t taxi_mutex=PTHREAD_MUTEX_INITIALIZER;// sync mutex

void *traveler_arrive(void *name)
{
    cout<<"Traveler:"<<(char*)name<<" needs a taxi now!"<<endl;
    pthread_mutex_lock(&taxi_mutex);
    pthread_cond_wait(&taxi_cond,&taxi_mutex);
    pthread_mutex_unlock(&taxi_mutex);
    cout<<"Traveler:"<<(char*)name<<" now got a taxi!"<<endl;
    pthread_exit((void*)0);
}

void *taxi_arrive(void *name)
{
    cout<<"Taxi:"<<(char*)name<<" arriver."<<endl;
    pthread_cond_signal(&taxi_cond);
    pthread_exit((void*)0);
}

int main()
{
    pthread_t tids[3];
    int flag;

    flag=pthread_create(&tids[0],NULL,taxi_arrive,(void*)("Jack"));
    if(flag)
    {
        cout<<"pthread_create error:flag="<<flag<<endl;
        return flag;
    }
    cout<<"time passing by"<<endl;
    sleep(1);

    flag=pthread_create(&tids[1],NULL,traveler_arrive,(void*)("Susan"));
    if(flag)
    {
        cout<<"pthread_create error:flag="<<flag<<endl;
        return flag;
    }
    cout<<"time passing by"<<endl;
    sleep(1);

    flag=pthread_create(&tids[2],NULL,taxi_arrive,(void*)("Mike"));
    if(flag)
    {
        cout<<"pthread_create error:flag="<<flag<<endl;
        return flag;
    }
    cout<<"time passing by"<<endl;
    sleep(1);

    void *ans;
    for(int i=0; i<3; i++)
    {
        flag=pthread_join(tids[i],&ans);
        if(flag)
        {
            cout<<"pthread_join error:flag="<<flag<<endl;
            return flag;
        }
        cout<<"ans="<<ans<<endl;
    }
    return 0;
}

分析:程序由一個條件變量,用于提示乘客有出租車到達,還有一個同步鎖,乘客到達之后就是等車(條件變量),出租車到達之后就是通知乘客,我們看到乘客Susan到達之后,并沒有乘坐先到的Jack的車,而是等到Mike的車到了之后再乘坐Mike的車,Jack的車白白的閑置了,為什么會造成這種原因呢?分析一下代碼:我們發現Jack出租車到達之后調用pthread_cond_signal(&taxi_cond)發現沒有乘客,然后就直接結束線程了。。。。

正確的操作應該是:先到的Jack發現沒有乘客,然后一直等待乘客,有乘客到了就直接走,而且我們應該統計一下乘客的數量

做如下改進:

1.增加乘客計數器,使得出租車在有乘客到達之后可以直接走,而不是又在原地等待別的乘客(僵死線程)

2.出租車到達函數加個while循環,沒有乘客的時候一直等待,直到乘客到來

#include <iostream>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
using namespace std;

pthread_cond_t taxi_cond=PTHREAD_COND_INITIALIZER; //taix arrive cond
pthread_mutex_t taxi_mutex=PTHREAD_MUTEX_INITIALIZER;// sync mutex


void *traveler_arrive(void *name)
{
    cout<<"Traveler:"<<(char*)name<<" needs a taxi now!"<<endl;
    pthread_mutex_lock(&taxi_mutex);
 
    pthread_cond_wait(&taxi_cond,&taxi_mutex);
    pthread_mutex_unlock(&taxi_mutex);
    cout<<"Traveler:"<<(char*)name<<" now got a taxi!"<<endl;
    pthread_exit((void*)0);
}

void *taxi_arrive(void *name)
{
    cout<<"Taxi:"<<(char*)name<<" arriver."<<endl;
    
    pthread_exit((void*)0);
}

int main()
{
    pthread_t tids[3];
    int flag;

    flag=pthread_create(&tids[0],NULL,taxi_arrive,(void*)("Jack"));
    if(flag)
    {
        cout<<"pthread_create error:flag="<<flag<<endl;
        return flag;
    }
    cout<<"time passing by"<<endl;
    sleep(1);

    flag=pthread_create(&tids[1],NULL,traveler_arrive,(void*)("Susan"));
    if(flag)
    {
        cout<<"pthread_create error:flag="<<flag<<endl;
        return flag;
    }
    cout<<"time passing by"<<endl;
    sleep(1);

    flag=pthread_create(&tids[2],NULL,taxi_arrive,(void*)("Mike"));
    if(flag)
    {
        cout<<"pthread_create error:flag="<<flag<<endl;
        return flag;
    }
    cout<<"time passing by"<<endl;
    sleep(1);

    void *ans;
    for(int i=0; i<3; i++)
    {
        flag=pthread_join(tids[i],&ans);
        if(flag)
        {
            cout<<"pthread_join error:flag="<<flag<<endl;
            return flag;
        }
        cout<<"ans="<<ans<<endl;
    }
    return 0;
}

三.讀寫鎖

可以多個線程同時讀,但是不能多個線程同時寫

1.讀寫鎖比互斥鎖更加具有適用性和并行性

2.讀寫鎖最適用于對數據結構的讀操作讀操作次數多余寫操作次數的場合!

3.鎖處于讀模式時可以線程共享,而鎖處于寫模式時只能獨占,所以讀寫鎖又叫做共享-獨占鎖

4.讀寫鎖有兩種策略:強讀同步和強寫同步

在強讀同步中,總是給讀者更高的優先權,只要寫者沒有進行寫操作,讀者就可以獲得訪問權限

在強寫同步中,總是給寫者更高的優先權,讀者只能等到所有正在等待或者執行的寫者完成后才能進行讀

不同的系統采用不同的策略,比如航班訂票系統使用強寫同步,圖書館查閱系統采用強讀同步

根據不同的業務場景,采用不同的策略

1)初始化的銷毀讀寫鎖

靜態初始化:pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER

動態初始化:int pthread_rwlock_init(rwlock,NULL),NULL代表讀寫鎖采用默認屬性

銷毀讀寫鎖:int pthread_rwlock_destory(rwlock)

在釋放某個讀寫鎖的資源之前,需要先通過pthread_rwlock_destory函數對讀寫鎖進行清理。釋放由pthread_rwlock_init函數分配的資源

如果你想要讀寫鎖使用非默認屬性,則attr不能為NULL,得給attr賦值

int pthread_rwlockattr_init(attr),給attr初始化

int pthread_rwlockattr_destory(attr),銷毀attr

2)以寫的方式獲取鎖,以讀的方式獲取鎖,釋放讀寫鎖

int pthread_rwlock_rdlock(rwlock),以讀的方式獲取鎖

int pthread_rwlock_wrlock(rwlock),以寫的方式獲取鎖

int pthread_rwlock_unlock(rwlock),釋放鎖

上面兩個獲取鎖的方式都是阻塞的函數,也就是說獲取不到鎖的話,調用線程不是立即返回,而是阻塞執行,在需要進行寫操作的時候,這種阻塞式獲取鎖的方式是非常不好的,你想一下,我需要進行寫操作,不但沒有獲取到鎖,我還一直在這里等待,大大拖累效率

所以我們應該采用非阻塞的方式獲取鎖:

int pthread_rwlock_tryrdlock(rwlock)

int pthread_rwlock_trywrlock(rwlock)

讀寫鎖的樣例:

#include <iostream>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
using namespace std;

int num=5;
pthread_rwlock_t rwlock;

void *reader(void *arg)
{
  pthread_rwlock_rdlock(&rwlock);
  cout<<"reader "<<(long)arg<<" got the lock"<<endl;
  pthread_rwlock_unlock(&rwlock);
  return 0;
}

void *writer(void *arg)
{
  pthread_rwlock_wrlock(&rwlock);
  cout<<"writer "<<(long)arg<<" got the lock"<<endl;
  pthread_rwlock_unlock(&rwlock);
  return 0;
}

int main()
{
  int flag;
  long n=1,m=1;
  pthread_t wid,rid;
  pthread_attr_t attr;

  flag=pthread_rwlock_init(&rwlock,NULL);
  if(flag)
  {
    cout<<"rwlock init error"<<endl;
    return flag;
  }

  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//thread sepatate

  for(int i=0;i<num;i++)
  {
    if(i%3)
    {
      pthread_create(&rid,&attr,reader,(void *)n);
      cout<<"create reader "<<n<<endl;
      n++;
    }else
    {
      pthread_create(&wid,&attr,writer,(void *)m);
      cout<<"create writer "<<m<<endl;
      m++;
    }
  }

  sleep(5);//wait other done
  return 0;
}

分析:3個讀線程,2個寫線程,讀線程比寫線程多

當讀寫鎖是寫狀態時,在鎖被解鎖之前,所有試圖對這個鎖加鎖的線程都會被阻塞

當讀寫鎖是讀狀態時,在鎖被解鎖之前,所有視圖以讀模式對它進行加鎖的線程都可以得到訪問權,但是以寫模式對它進行加鎖的線程會被阻塞

所以讀寫鎖默認是強讀模式!

四.信號量

信號量(sem)和互斥鎖的區別:互斥鎖只允許一個線程進入臨界區,而信號量允許多個線程進入臨界區

1)信號量初始化

int sem_init(&sem,pshared,v)

pshared為0表示這個信號量是當前進程的局部信號量

pshared為1表示這個信號量可以在多個進程之間共享

v為信號量的初始值

成功返回0,失敗返回-1

2)信號量值的加減

int sem_wait(&sem):以原子操作的方式將信號量的值減去1

int sem_post(&sem):以原子操作的方式將信號量的值加上1

3)對信號量進行清理

int sem_destory(&sem)

通過信號量模擬2個窗口,10個客人進行服務的過程

樣例:

#include <iostream>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<semaphore.h>
using namespace std;


int num=10;
sem_t sem;

void *get_service(void *cid)
{
  int id=*((int*)cid);
  if(sem_wait(&sem)==0)
  {
     sleep(5);
     cout<<"customer "<<id<<" get the service"<<endl;
     cout<<"customer "<<id<<" done "<<endl;
     sem_post(&sem);
  }
  return 0;
}

int main()
{
  sem_init(&sem,0,2);
  pthread_t customer[num];
  int flag;

  for(int i=0;i<num;i++)
  {
    int id=i;
    flag=pthread_create(&customer[i],NULL,get_service,&id);
    if(flag)
    {
      cout<<"pthread create error"<<endl;
      return flag;
    }else
    {
      cout<<"customer "<<i<<" arrived "<<endl;
    }
    sleep(1);
  }

  //wait all thread done
  for(int j=0;j<num;j++)
  {
    pthread_join(customer[j],NULL);
  }
  sem_destroy(&sem);
  return 0;
}

分析:信號量的值代表空閑的服務窗口,每個窗口一次只能服務一個人,有空閑窗口,開始服務前,信號量-1,服務完成后信號量+1

總結完畢:Linux c++線程同步的四種方式:互斥鎖,條件變量,讀寫鎖,信號量

到此這篇關于超詳細講解Linux C++多線程同步的方式的文章就介紹到這了,更多相關Linux C++多線程同步內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

標簽:泰州 周口 朝陽 那曲 蕪湖 慶陽 銅川 松原

巨人網絡通訊聲明:本文標題《超詳細講解Linux C++多線程同步的方式》,本文關鍵詞  超,詳細,講解,Linux,C++,多,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《超詳細講解Linux C++多線程同步的方式》相關的同類信息!
  • 本頁收集關于超詳細講解Linux C++多線程同步的方式的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    91精品国产全国免费观看 | 成人av一区二区三区| 亚洲国产va精品久久久不卡综合| 国产日韩欧美在线一区| 精品国产免费一区二区三区四区| 欧美日韩成人综合| 欧美日韩中文字幕一区| 在线影视一区二区三区| 91福利在线免费观看| 成人av在线网| 91丨九色porny丨蝌蚪| 一本久久精品一区二区| 成人免费va视频| 成人av手机在线观看| av一区二区三区在线| 亚洲成人一区在线| 日本人妖一区二区| 97成人超碰视| 国产欧美一区二区精品婷婷| 九九**精品视频免费播放| 欧美色综合天天久久综合精品| 欧美韩日一区二区三区| 久久成人久久爱| 欧美日韩国产片| 亚洲一区二区综合| 成人短视频下载| 2021国产精品久久精品| 久久国产麻豆精品| 91麻豆精品国产自产在线 | 粉嫩绯色av一区二区在线观看 | 欧美日韩精品一二三区| 日韩一级片在线播放| 欧美伦理电影网| 欧美一区二区精美| 久久久久久久免费视频了| 亚洲欧洲日韩女同| 亚洲综合免费观看高清完整版在线| 亚洲最大成人网4388xx| 美女一区二区久久| 成人精品鲁一区一区二区| 色婷婷av一区二区三区大白胸| 91麻豆精品久久久久蜜臀| 久久蜜桃av一区精品变态类天堂 | 日韩精品亚洲一区| 激情欧美日韩一区二区| av欧美精品.com| 欧美日韩另类国产亚洲欧美一级| 久久久噜噜噜久久中文字幕色伊伊 | 久久一二三国产| 一区二区三区四区五区视频在线观看| 日韩二区三区四区| 成人伦理片在线| 精品美女一区二区三区| 亚洲一区在线观看免费| 99国产精品久久久久| 日韩一区二区在线观看视频播放| 成人欧美一区二区三区1314| 老色鬼精品视频在线观看播放| 色哦色哦哦色天天综合| 国产欧美视频一区二区三区| 一区二区国产视频| 国产精品一区二区男女羞羞无遮挡 | 亚洲最新视频在线播放| 大陆成人av片| 精品福利在线导航| 日日嗨av一区二区三区四区| 亚洲图片欧美视频| 欧美亚洲国产一区二区三区va| 免费成人在线视频观看| 中国色在线观看另类| 欧美性xxxxxx少妇| 精品午夜一区二区三区在线观看| 国产精品动漫网站| 91麻豆精品国产自产在线观看一区| 久久精品国产99久久6| 国产精品青草综合久久久久99| 欧美色电影在线| 国产高清不卡二三区| 亚洲午夜免费视频| 国产女同互慰高潮91漫画| 欧美午夜精品久久久久久超碰| 狠狠色丁香婷婷综合久久片| 亚洲特黄一级片| 日韩欧美国产综合| 五月婷婷综合网| 久久成人综合网| 国产无人区一区二区三区| 成人一区二区视频| 亚洲视频你懂的| 在线观看成人小视频| 五月天丁香久久| 欧美大肚乱孕交hd孕妇| 极品少妇xxxx精品少妇| 久久网站热最新地址| 国产福利一区二区三区在线视频| 国产精品网站在线观看| 99精品欧美一区| 亚洲国产欧美另类丝袜| 欧美高清性hdvideosex| 日本午夜精品视频在线观看| 3d动漫精品啪啪一区二区竹菊| 婷婷综合在线观看| 欧美一级片在线看| 国产在线精品一区二区夜色 | 美女在线一区二区| 国产色一区二区| 欧美在线综合视频| 婷婷久久综合九色综合绿巨人| 精品国产精品网麻豆系列| 国产成人精品在线看| 国产精品不卡在线观看| 91成人在线精品| 狠狠色伊人亚洲综合成人| 国产欧美久久久精品影院| 欧美亚洲自拍偷拍| 国产一区二区三区精品欧美日韩一区二区三区 | 亚洲免费视频成人| 日韩精品一区二区在线观看| 99麻豆久久久国产精品免费 | 国产欧美日韩在线| 欧美影视一区在线| 国产精品一线二线三线精华| 五月天欧美精品| 最新中文字幕一区二区三区| 日韩一级免费一区| 91麻豆国产在线观看| 国产精品自拍一区| 日韩电影在线一区二区| 最新国产精品久久精品| 精品国产一区二区三区不卡| 91啦中文在线观看| 成人激情电影免费在线观看| 青椒成人免费视频| 亚洲va欧美va人人爽| 欧美精品一区二区三区蜜桃视频| 欧美第一区第二区| 国产欧美一区二区三区鸳鸯浴 | 亚洲不卡av一区二区三区| 无吗不卡中文字幕| 日韩av一区二| 国产成人在线观看免费网站| 99免费精品视频| 欧美精品xxxxbbbb| 精品国产三级a在线观看| 精品精品国产高清a毛片牛牛| 中文字幕一区在线| 亚洲人成网站在线| 日韩av一区二区三区| 高清不卡在线观看| 91免费看视频| 欧美福利一区二区| 国产亚洲一区二区三区在线观看| 国产精品久久久久久久浪潮网站| 亚洲综合激情小说| 久久一夜天堂av一区二区三区 | 国产精品入口麻豆原神| 久久久91精品国产一区二区精品 | 成人免费av网站| 风间由美性色一区二区三区| 懂色一区二区三区免费观看| 奇米四色…亚洲| 精久久久久久久久久久| 国产一区二区三区四区在线观看| 黄色日韩网站视频| 狠狠久久亚洲欧美| 成人在线综合网| 成人黄色电影在线 | 欧美日韩视频在线第一区| 欧美色倩网站大全免费| 91精品中文字幕一区二区三区| 色婷婷av一区二区| 在线电影一区二区三区| 欧美日韩国产天堂| 欧美一区二区三区视频免费| 日韩欧美亚洲国产精品字幕久久久 | 欧美性xxxxx极品少妇| 91麻豆精品国产| 国产日韩一级二级三级| 亚洲欧美另类图片小说| 婷婷中文字幕一区三区| 国产在线播放一区二区三区| 成人教育av在线| 欧美日韩视频在线观看一区二区三区 | 国产精品久久久久久久久免费丝袜 | 色婷婷久久99综合精品jk白丝| 欧美日韩国产美女| 2020日本不卡一区二区视频| 国产精品日日摸夜夜摸av| 日韩毛片精品高清免费| 日本亚洲天堂网| jlzzjlzz亚洲女人18| 91精品国产一区二区人妖| 久久久久久影视| 亚洲国产中文字幕在线视频综合| 久久99九九99精品| 色综合久久久久网| 久久香蕉国产线看观看99| 综合久久久久综合| 国产在线视频不卡二| 欧美日韩一区二区三区不卡|