1. 程式人生 > >多執行緒中 關於條件變數和互斥鎖的疑惑(純乾貨)

多執行緒中 關於條件變數和互斥鎖的疑惑(純乾貨)

條件變數的執行過程(虛擬碼)

int pthread_cond_wait(&cond,&wait)
{  
  int ret = pthread_cond_wait_and unlock(&cond,&wait);//進入阻塞狀態後解鎖
  pthread_mutex_lock(&lock);//再去競爭鎖
  return ret
}

條件變數為什麼要搭配互斥鎖

1 條件變數的改變一般是臨界資源來完成的,那麼修改臨界資源首先應該加鎖
而執行緒在條件不滿足的情況下要阻塞,等待別人喚醒,
那麼在阻塞後一定要把鎖放開,等到合適的執行緒拿到鎖去修改臨界資源,否則會出現死鎖

2 線上程被喚醒後第一件事也應該是爭取拿到鎖,恢復以前加鎖的狀態.

否則在執行條件變數成立後的程式碼也法保證其原子性

所以條件變數和鎖是相輔相成的:

條件變數需要鎖的保護
鎖需要 條件變數成立後,後重新上鎖

條件變數為什麼要使用while迴圈判斷,而不是if

首先我們應該瞭解,條件變數是用來阻塞或者喚醒執行緒的,

阻塞和喚醒是依靠訊號機制來處理的,

條件變數中的條件是我們自己規定的,

也就是說當條件成立後,作業系統給阻塞程序傳送訊號,喚醒這個程序

那萬一作業系統抽風了,隨便給程序傳送喚醒訊號 (此時條件還沒成立),

執行緒醒了之後就會在條件沒成立的情況下執行之後的程式碼

這也是第一點 用if 不能保證bug訊號的有效處理, 但是
while()
{
cond_wait(&cond,&mutex);
}
喚醒操作後如果再次競爭到鎖,第一件事就是再次進入while 看條件是否成立 能有效杜絕bug訊號

2.
生產消費者模型, 生產者生產一個產品,兩個消費者 A和B 同時競爭這一個產品

假定是兩個消費者都先後拿到鎖,發現沒有商品然後睡眠放鎖
此時必定生產者得到鎖,生產一個產品,然後退出
當用broadcat或者signal喚醒消費者時,
假設消費者A先拿到了鎖 消費完產品之後退出
B後拿到鎖, 因為是while 迴圈,又會執行一次判斷 發現沒有產品, 接著進入等待

如果 此時條件判斷改成if 消費者b在wait被喚醒後 會直接執行接下來的消費語句

會發現生產者之只生產了1個產品,喚醒了兩個消費者,兩個消費者同時”消費”了一個產品
錯誤!
驗證程式碼

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
int flag = 0;

void* product(void* msg)
{
    char* who = (char*) msg;
    pthread_mutex_lock(&mutex);
    flag = 1;
    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&mutex);
    return NULL;
}
void* consume(void* msg)
{
    char* who = (char*) msg;
    pthread_mutex_lock(&mutex);
    while(flag == 0)
        pthread_cond_wait(&cond, &mutex);
    printf(" %s said : i got the flag\n", who);
    flag = 0;
    pthread_mutex_unlock(&mutex);
    return NULL;
}
int main()
{
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    pthread_t producter, consumer_1, consumer_2;
    pthread_create(&producter, NULL, product, "producter");
    pthread_create(&consumer_1, NULL, consume, "consumer_1");
    pthread_create(&consumer_2, NULL, consume, "consumer_2");
    pthread_join(producter, NULL);
    pthread_join(consumer_1, NULL);
    pthread_join(consumer_2, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
}

相關推薦

linux下執行條件變數的用法

使用條件變數最大的好處是可以避免忙等。相當與多執行緒中的訊號。 條件變數是執行緒中的東西就是等待某一條件的發生和訊號一樣以下是說明,條件變數使我們可以睡眠等待某種條件出現。條件變數是利用執行緒間共享的全域性變數進行同步的一種機制,主要包括兩個動作:一個執行緒等待"條件變數的條件成立"而掛起;另一個執行緒

執行 關於條件變數互斥疑惑(乾貨)

條件變數的執行過程(虛擬碼) int pthread_cond_wait(&cond,&wait) { int ret = pthread_cond_wait_and unlock(&cond,&wait);//進入

執行程式設計總結(二)——條件變數互斥

#include <stdio.h> #include <pthread.h> #include <error.h> #include <assert.h> #include <stdlib.h> typedef int DataType; typ

Java執行Synchronized簡介Static Synchronized的區別

在進行Java開發時,多執行緒的開發是經常會使用的。首先會問一個小問題啊,在Java中有幾種方法可以建立一個執行緒? 我給的答案是3種。(如果還有其他的請留言告訴我哈。) 1、建立直接繼承自Thread類建立執行緒子類。   步驟如下:a 定義一個子類,同時

PYTHON——執行條件變數(Condition)

  條件變數(Condition)也是一把鎖,除了同步鎖的作用外,還具有線上程間通訊的功能。   有一類執行緒需要滿足條件之後才能夠繼續執行,Python提供了threading.Condition 物件用於條件變數執行緒的支援,它除了能提供RLock()或Lock()的方法外,還提供了 wait()、no

c/c++ 執行 利用條件變數實現執行安全的佇列

多執行緒 利用條件變數實現執行緒安全的佇列 背景:標準STL庫的佇列queue是執行緒不安全的。 利用條件變數(Condition variable)簡單實現一個執行緒安全的佇列。 程式碼: #include <queue> #include <memory> #include

執行總記憶體執行的工作記憶體

Java記憶體模型將記憶體分為了 主記憶體和工作記憶體 。類的狀態,也就是類之間共享的變數,是儲存在主記憶體中的,每個執行緒都有一個自己的工作記憶體(相當於CPU高階緩衝區,這麼做的目的還是在於進一步縮小儲存系統與CPU之間速度的差異,提高效能),每次Java

執行程式設計——條件變數

#include <pthread.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> /* 靜態方式初始化一個互斥鎖和一個條件變數 */ static pthread

Java執行的finalstatic

看Android的多執行緒發現其實是Java的多執行緒。我找了一本Java程式設計思想學習Java的併發機制。寫了一個demo,遇到一些問題,雖然最後想明白了,但是也暴露了我的Java基礎差勁的事實。之後我會通過寫部落格的方式來提高Java水平。現在說一下我的問

Java執行static變數的使用 SimpleDateFormat時間格式化存線上程安全問題

兩篇文章 Java多執行緒中static變數的使用  (轉自:http://blog.csdn.net/yy304935305/article/details/52456771) &&  SimpleDateFormat時間格式化存線上程安全問題

iOS執行,佇列執行的排列組合結果分析

本文是對以往學習的多執行緒中知識點的一個整理。 多執行緒中的佇列有:序列佇列,併發佇列,全域性佇列,主佇列。 執行的方法有:同步執行和非同步執行。那麼兩兩一組合會有哪些注意事項呢? 如果不是在董鉑然部落格園看到這邊文章請 點選檢視原文 提到多執行緒,也就是四種,pthread,NSthread,GCD

執行的wait()notify()方法

wait()和notify()方法屬於Object類中的方法,是用於對執行緒之間進行資源物件鎖的通訊,其必須在synchronized(Obj){...}語法塊內 wait()就是說執行緒在獲取物件鎖後,主動釋放物件鎖,同時本執行緒進行休眠。直到有其它執行緒呼叫該物件的no

Java執行,JoinInterrupt()方法的使用

更多詳細的解答請轉至:http://my.oschina.net/summerpxy/blog/198457;http://uule.iteye.com/blog/1101994;(比如有一個執行緒t.當在Main執行緒中呼叫t.join()的時候,那麼Main執行緒必須拿

java之執行Thread類Runnable介面使用方法

java提供了兩種執行緒方式,一種是繼承java.lang包下的Thread類,覆寫Thread類的run()方法,在run()方法中實現執行線上程上的程式碼!第二種是實現Runnable介面建立多執行

執行全域性變數成員變數

線上程中,run方法中呼叫的變數不同,那麼程式執行的結果也不同,變數屬於成員變數還是屬於區域性變數,要處理物件的變數還是方法中的變數會導致結果的差異性。 1)執行緒處理了全域性變數 package

執行wait(),notify()notifyall()方法的含義

在“synchronized(obj){··········}”這個同步塊中,obj物件叫做監控器,只有持有監控器這個物件的鎖時才會執行同步塊中的內容Java中的執行緒的生命週期大體可分為5種狀態。1. 新建(NEW):新建立了一個執行緒物件。2. 可執行(RUNNABLE)

執行-----經典解釋監視器物件

在JVM的規範中,有這麼一些話:      “在JVM中,每個物件和類在邏輯上都是和一個監視器相關聯的”        “為了實現監視器的排他性監視能力,JVM為每一個物件和類都關聯一個鎖”      “鎖住了一個物件,就是獲得物件相關聯的監視器”      從這些話,

執行條件變數虛假喚醒(Spurious wakeup)

這是因為可能會存在虛假喚醒”spurious wakeup”的情況。也就是說,即使沒有執行緒呼叫condition_signal, 原先呼叫condition_wait的函式也可能會返回。此時執行緒被喚醒了,但是條件並不滿足,這個時候如果不對條件進行檢查而往下執行,就可能會導致後續的處理出現錯誤。 虛假喚醒

【併發】執行程式設計條件變數虛假喚醒的討論

轉自:http://blog.csdn.net/puncha/article/details/8493862 From: http://siwind.iteye.com/blog/1469216 From:http://en.wikipedia.org/wiki/S

Linux Qt使用POSIX執行條件變數互斥(量)

今天團建,但是文章也要寫。酒要喝好,文要寫美,方為我輩程式設計師的全才之路。嘎嘎   之前一直在看POSIX的多執行緒程式設計,上個週末結合自己的理解,寫了一個基於Qt的用條件變數同步執行緒的例子。故此來和大家一起分享,希望和大家一起交流。   提到執行緒,如果在UI程式設計中,總