理解pthread_cond_wait()和pthread_cond_signal()

时间:2013-05-13 13:07:55

标签: c++ multithreading mutex

一般来说,pthread_cond_wait()pthread_cond_signal()的调用方式如下:

//thread 1:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
do_something()
pthread_mutex_unlock(&mutex);

//thread 2:
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);  
pthread_mutex_unlock(&mutex);

步骤

  1. pthread_cond_wait(&cond, &mutex);被调用,它解锁了互斥锁

  2. 线程2锁定互斥锁并调用pthread_cond_signal(),解锁互斥锁

  3. 在主题1中,调用pthread_cond_wait()并再次锁定互斥锁

  4. 现在在线程2中,在pthread_cond_signal()被调用之后,pthread_mutex_unlock(&mutex)将会运行,在我看来它想要解锁现在被线程1锁定的互斥锁。有没有什么我理解错了吗?

    此外,在我看来,pthread_cond_wait()只能被同一个cond-mutex对的1个线程调用。但有一种说法是“pthread_cond_signal()函数应解除阻塞在指定条件变量cond上阻塞的至少一个线程(如果在cond上阻塞了任何线程)。”那么,这意味着同一个cond-mutex对的多个线程可以调用pthread_cond_wait()

3 个答案:

答案 0 :(得分:69)

pthread_cond_signal无法解锁互斥锁(因为它没有引用互斥锁,所以它怎么能知道解锁什么?)实际上,信号不需要与互斥锁有任何连接;信令线程不需要保持互斥锁,但对于大多数基于条件变量的算法,它都会。

pthread_cond_wait在睡眠之前解锁互斥锁(正如您所注意到的),但是当它被唤醒时,它会在发出信号时重新获取互斥锁(可能需要等待)。因此,如果信令线程持有互斥锁(通常情况),则等待线程将不会继续,直到信令线程也解锁互斥锁。

条件变量的常见用法如下:

thread 1:
    pthread_mutex_lock(&mutex);
    while (!condition)
        pthread_cond_wait(&cond, &mutex);
    /* do something that requires holding the mutex and condition is true */
    pthread_mutex_unlock(&mutex);

thread2:
    pthread_mutex_lock(&mutex);
    /* do something that might make condition true */
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);

这两个线程有​​一些共享数据结构,互斥锁正在保护访问权限。第一个线程想要等到某个条件为真,然后立即执行一些操作(没有竞争条件机会让某些其他线程进入条件检查和操作之间并使条件为假。)第二个线程正在做一些可能的事情使条件成立,所以它需要唤醒任何可能正在等待它的人。

答案 1 :(得分:6)

以下是一个典型的例子:线程1正在等待一个条件,这可以由第2个线程来完成。

我们使用一个互斥锁和一个条件。

pthread_mutex_t mutex;
pthread_cond_t condition;

主题1:

pthread_mutex_lock(&mutex); //mutex lock
while(!condition){
    pthread_cond_wait(&condition, &mutex); //wait for the condition
}

/* do what you want */

pthread_mutex_unlock(&mutex);

主题2:

pthread_mutex_lock(&mutex);

/* do something that may fulfill the condition */

pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condition); //wake up thread 1

修改

正如您在pthread_cond_wait manual中所看到的那样:

它自动释放互斥锁并导致调用线程阻塞条件变量cond;原子地这里的意思是“相对于另一个线程访问互斥锁然后条件变量的原子性”。

答案 2 :(得分:0)

我从这里举了个例子 https://www.geeksforgeeks.org/condition-wait-signal-multi-threading/

并对此进行了修改,

#include <pthread.h> 
#include <stdio.h> 
#include <unistd.h> 

// Declaration of thread condition variable 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

// declaring mutex 
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 

// Thread function 
void releaseFun() 
{ 
    // Let's signal condition variable cond
    printf("Signaling condition variable cond\n"); 
    pthread_cond_signal(&cond); 
}

// Thread function 
void* blockedThread() 
{
    // acquire a lock 
    pthread_mutex_lock(&lock); 
    printf("Waiting on condition variable cond\n");
    pthread_cond_wait(&cond, &lock); 
    // release lock 
    pthread_mutex_unlock(&lock); 

    printf("Returning thread\n"); 

    return NULL; 
}    

// Driver code 
int main() 
{ 
    pthread_t tid;

    // Create thread 1 
    pthread_create(&tid, NULL, blockedThread, NULL); 

    // sleep for 1 sec so that thread 1 
    // would get a chance to run first 
    sleep(1); 

    releaseFun();
    // wait for the completion of thread 2 
    pthread_join(tid, NULL); 

    return 0; 
}

输出:gcc test_thread.c -lpthread

等待条件变量cond

信号条件变量cond

返回线程

仅当发出信号指示blockThread的pthread_cond_wait()函数被解除锁定时,才会发生线程的锁定和解锁。