【问题标题】:pthread_cond_timedwait() & pthread_cond_broadcast() explainedpthread_cond_timedwait() & pthread_cond_broadcast() 解释
【发布时间】:2014-02-13 12:23:09
【问题描述】:

所以我搜索了堆栈溢出和其他资源的高低,但对于上述功能,我无法理解一些事情。具体来说,

1)当pthread_cond_timedwait()因为定时器值用完而返回时,它如何自动重新获取互斥锁。互斥锁可能被锁定在别处。例如,在生产者-消费者队列中,消费者可能正在等待使用 timedwait() 变体。从我读过的解释来看,当线程唤醒时,似乎会自动重新获取互斥锁。这让我很困惑?还是说它会在定时器用完后唤醒,然后再检查谓词并再次加锁。这没有意义?

2)当一堆线程已经获得一个互斥体并且现在都在等待一个简单的 pthread_cond_wait() 时,如果另一个线程发出 pthread_cond_broadcast() 会发生什么。每个线程(由调度程序决定)是否会一个接一个地唤醒,依次获取互斥锁,然后每个线程继续执行?或者只会唤醒整个线程列表中的一个线程。我假设使用 pthread_cond_signal() 也可以实现这两种行为中的后者。此外,如果前面的方法是正确的行为,那么我们可以假设某个其他线程可能最终会在其他地方对变量调用 wait()。然后将所有这些其他等待线程重新置于阻塞状态并等待信号。还是每个人都会继续觉醒,一个一个进步?

【问题讨论】:

    标签: c++ multithreading pthreads posix


    【解决方案1】:

    如果pthread_cond_timedwait()由于超时而返回,它会在返回之前重新获取互斥锁。这可能意味着它必须等待互斥锁被解锁,如果它当时被另一个线程锁定。本质上,它的行为就像在返回之前调用了pthread_mutex_lock()

    pthread_cond_broadcast()被调用时,所有等待的线程都会被唤醒,这意味着它们都会尝试获取互斥体并返回。当然,互斥锁会序列化这个,所以它们一次只会返回一个。此后发生什么都无关紧要 - 这些线程一旦获得互斥体,最终都会从它们的pthread_cond_wait() 调用中返回。另一个调用pthread_cond_wait() 的线程不会影响这一点。

    【讨论】:

      【解决方案2】:

      (1) pthread_cond_timedwait()

      一个简短(浅薄)的解释它是如何工作的。

      1) 与 pthread_cond_timewait() 关联的互斥锁应在调用该函数之前锁定。你有责任去做。否则,函数行为未定义。

      2) 当您的程序将其控制权转移给函数时,函数会原子地释放关联的互斥体,让其他线程有机会获取它。当您等待时,互斥锁被解锁。解锁它是功能责任。 如果函数实现做不到,只有一个线程会处理关联的互斥体。

      3) 当函数返回时,无论是由于超时还是由于接收到信号,该函数都会自动锁定互斥体。锁定互斥锁是函数的职责。

      4) 现在你应该再次解锁互斥锁。

      解释中的“原子”一词意味着函数本身是线程安全的。

      (2) pthread_cond_broadcast()

      使用 pthread_cond_broadcast() 发出信号会导致所有等待的线程唤醒并开始一一处理。使用 pthread_cond_signal() 发出信号只会唤醒一个线程。要“感受”这个概念,您可以使用以下说明该想法的代码。将 pthread_cons_signal 替换为 pthread_cond_brodcast。考虑到使用 pthread_cons_signal 时程序永远不会终止:只有一个等待线程获取信号并退出等待循环。

      #include <stdio.h>
      #include <stdlib.h>
      #include <pthread.h>
      #include <unistd.h>
      
      pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
      int value = 0;
      
      void* waiter(void* arg)
      {
        int* tid = (int*)arg;
      
        printf("waiter started %d\n", *tid);
      
        pthread_mutex_lock(&mutex);
        while(value == 0)
        {
          pthread_cond_wait(&cond, &mutex);
        }
        sleep(10);
        printf("waiter %d releases\n", *tid);
        pthread_mutex_unlock(&mutex);
      
      }
      
      void* notifier(void* arg)
      {
        sleep(2);
        pthread_mutex_lock(&mutex);
        value = 1;
        //pthread_cond_broadcast(&cond);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
      }
      
      int main(void)
      {
        pthread_t w1; // waiter
        int tid1=1;
        pthread_t w2; // waiter
        int tid2=2;
        pthread_t n1; // notifier
      
        pthread_create(&w1, NULL, waiter, &tid1);
        pthread_create(&w2, NULL, waiter, &tid2);
        pthread_create(&n1, NULL, notifier, NULL);
      
        pthread_join(w1, NULL);
        pthread_join(w2, NULL);
        pthread_join(n1, NULL);
        return 0;
      }  
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-01
        • 1970-01-01
        • 2012-12-24
        • 1970-01-01
        • 2012-09-02
        • 1970-01-01
        • 2010-10-14
        • 2013-04-07
        相关资源
        最近更新 更多