前言: 線程之間資源共享,所以不存在通信問題,但是會有很強烈的競爭問題,解決線程之間的競爭問題有以下幾種方法:
注:加鎖不要太大,也盡量不要太多,否則會影響效率,讀寫鎖結束最好放棄cpu調度
1.互斥量
功能:保證同一時間只有一個線程可以對共享資源進行操作,但是不保證同步
步驟:
1.1初始化互斥量:(2中方法,,一般常用靜態,靜態初始化用完后不需要刪除)
動態初始化:
static pthread_mutex_t mm;
prhread_mutex_init(&mm,NULL);
靜態初始化:
static pthread_mutex_t mm=PTHREAD_MUTEX_INITIALIZER;
1.2 加/解鎖操作
pthread_mutex_lock(&mm);//加鎖操作,未獲得鎖的線程則阻塞等待
pthread_mutex_trylock(&mm)//加鎖操作,未獲得鎖的線程則非0返回,繼續執行其他 非競爭任務
pthread_mutex_unlock(&mm)//解鎖操作,解鎖操作不會出錯,即使沒有鎖也可以解鎖
1.3 銷毀互斥量(鎖)
pthread_mutex_destroy(&mm)// 靜態申請的不用銷毀
2.讀寫鎖 :讀共享 寫獨占
功能:有時多個線程需要對同個資源進行讀寫操作時,可能會數據丟失等問題,如在寫的時 候發生了讀事件,而讀寫鎖可以有效保證 讀共享,寫獨占,主要用於既有讀,又有 寫,且讀的數量遠大於寫
優點:能夠實現線程的高並發,但是線程的調度還不夠精准(盲目調度)
注意:每個線程執行完后應該放棄自己的時間片,這樣可以解決線程飢餓問題
sched_yield() //放棄cpu調度
步驟:
2.1 初始化讀寫鎖(只能動態初始化)
static pthread_rwlock_t rw;//聲明一個全局鎖變量
pthread_rwlock_init(&rw,NULL)//初始化鎖
2.2 加/解鎖
pthread_rwlock_wrlock(&rw); //加一把寫鎖,若加鎖失敗則阻塞在此
pthread_rwlock_trywrlock(&rw); //加寫鎖,若加鎖失敗則立即返回非0值執行其他工作
pthread_rwlock_rdlock(&rw); //加一把讀鎖,失敗阻塞
pthread_rwlock_tryrdlock(&rw); //加讀鎖,失敗非阻塞
pthread_rwlock_unlock(&rw); //解鎖(不分類型且不會失敗)
2.3 銷毀鎖
pthread_rwlock_ destroy(&rw);
3.條件變量
功能:可以更好的協調多個線程工作,使cpu不會盲目調度,需要執行的線程收到信號后則執行,收不到信號的則睡眠等待信號。 通常需要合互斥量配合使用。互斥量保證同一時間只能有一個線程工作,條件變量能指定某個線程工作
1初始化條件變量:(2種初始化方法,一般常用靜態)
1.靜態初始化條件變量
pthread_cond_t ok=PTHREAD_COND_INITIALIZER;//申請一個變量名為ok的條件變量
1.2 動態初始化條件變量:
pthread_cond_t ok;
pthread_cond_init(&ok,NULL);
2.步驟:
1.對競爭部分加互斥鎖 pthread_mutex_lock(&mm);
2.用while循環判斷標志位,保證線程是收到信號后被喚醒的
while(flag!=0) {pthread_cond_wait(&no_ok,&mm); }
***********操作函數部分***********
3.更改標志位 :flag
4.解鎖 pthread_mutex_unlock(&mm);
5.發送信號:pthread_cond_signal() 或 pthread_cond_broadcast()
無論哪種等待方式,都必須和一個互斥鎖配合,以防止多個線程同時請求 pthread_cond_wait((pthread_cond_timedwait(),下同)的競爭條件(Race Condition),且在調用 pthread_cond_wait()前必須由本線程加鎖(pthread_mutex_lock()),而在更新條件等待隊列以前,mutex保持鎖 定狀態,並在線程掛起進入等待前解鎖。在條件滿足從而離開pthread_cond_wait()之前,mutex將被重新加鎖,以與進入 pthread_cond_wait()前的加鎖動作對應。 執行pthread_cond_wait()時自動解鎖互斥量(如同執行了 pthread_unlock_mutex),並等待條件變量觸發。這時線程掛起,不占用 CPU 時間,直到條件變量被觸發。
因此,全過程可以描述為:
(1)pthread_mutex_lock()上鎖,
(2)pthread_cond_wait()等待,等待過程分解為為:解鎖--條件滿足--加鎖
(3)pthread_mutex_unlock()解鎖。
激發條件有兩種形式,pthread_cond_signal()激活一個等待該條件的線程,存在多個等待線程時按入隊順序激活其中一個;而pthread_cond_broadcast()則激活所有等待線程。 兩者 如果沒有等待的線程,則什么也不做。
while(1)
{
pthread_mutex_lock(&mm);//首先加一把互斥鎖,保證只有一個線程可以搶到鎖,防止競爭
while(flag!=0) //加個循環防止_wait()被意外喚醒,
{
pthread_cond_wait(&no_ok,&mm);//等待喚醒信號,進入等待且原子性釋放鎖,收到信號並醒來,且需要持有鎖,若加 鎖失敗則等待
}
printf("input>");
fgets(buf,4096,stdin);
flag=1;
pthread_mutex_unlock(&mm); //釋放鎖
pthread_cond_signal(&ok); //發送信號
}