【问题标题】:understanding of pthread_cond_wait() and pthread_cond_signal()理解 pthread_cond_wait() 和 pthread_cond_signal()
【发布时间】:2013-05-07 12:49:44
【问题描述】:

一般来说,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() 被调用并再次锁定互斥锁

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

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

【问题讨论】:

    标签: c++ multithreading mutex


    【解决方案1】:

    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)线程2锁mutext(2)在线程2,pthread_cond_signal被调用(3)在线程1,pthread_cond_wait发出信号,它需要重新获取mutext,但是现在它被步骤(1)锁定了,对吗?
    • @user1944267:线程 1 将无法重新获取锁(并继续),直到线程 2 调用 pthread_mutex_unlock。但由于这会在调用 pthread_cond_signal 返回后立即发生,因此延迟非常小。
    • @ChrisDodd,线程 1 中只有一个问题,就在 while 循环之前,我认为我们应该“做一些触发线程 2 的事情”,因为如果线程在线程 1 执行 pthread_wait_cond 之前是触发器,则信号丢失并且线程 1 将处于无限等待中
    • @Mouin:在这种情况下,条件为真,线程 1 不会等待。这个想法是“条件”和它之后的动作是无法检查和以原子方式完成的事情(一些复杂的条件和/或动作),因此使用互斥锁和条件变量使其有效地原子化——只要没有人做任何事情在不持有锁的情况下影响条件。
    • @ChrisDodd,感谢反馈“在这种情况下,条件为真,线程 1 不会等待”:通过触发线程 2,我并不意味着设置条件为真。在我看来,线程 1 必须在锁定互斥锁后立即告诉线程 2:“继续进行检查并将条件设置为 true”,此时线程 2 将尝试设置条件,但只有在线程 1 执行时才会在互斥锁上阻塞pthread_cond_wait 它得到了互斥锁。但在上面的代码中,我们不能保证线程 2 会在线程 1 执行等待后调用pthread_cond_signal
    【解决方案2】:

    这是一个典型的例子:线程 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 上; atomically 这里的意思是“原子地相对于另一个线程访问互斥体,然后是条件变量”。

    【讨论】:

    • 你看步骤:(1)线程2锁定mutext(2)在线程2,pthread_cond_signal被调用(3)在线程1,pthread_cond_wait发出信号,它需要重新获取mutext,但现在它被步骤(1)锁定了,是不是?
    • 诀窍是,在线程 1 中,pthread_cond_wait 会临时释放互斥锁。
    • 1) TH1 锁定互斥锁 2) TH1 解锁互斥锁(使用 pthread_cond) 3) TH2 锁定互斥锁 4) TH2 解锁互斥锁并发送信号 5) TH1 取回互斥锁 6) TH1解锁互斥锁
    • 在thread2中,pthread_cond_signal也可以在互斥锁被锁定时发出信号。
    • 当有多个“thread2”实例并且“其他”可能正在等待互斥锁时,当我“做一些可能实现的事情”时,我是否必须检查条件是否为假,因为下一个获得互斥锁的线程是 thread1 不安全?
    【解决方案3】:

    我从这里举了一个例子 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() 函数发出信号解除阻塞时,才会对线程进行锁定和解锁。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-16
      • 2015-08-18
      相关资源
      最近更新 更多