【问题标题】:posix thread mutex and condition variable usage in multiple producer多个生产者中的posix线程互斥锁和条件变量使用
【发布时间】:2015-09-14 08:16:18
【问题描述】:

我试图找出在多线程产生和单线程消耗的情况下互斥和条件变量的执行情况。

这里是示例代码:

#include<stdio.h>
#include<pthread.h>
int done = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
void *thr2(void *arg) {
     pthread_t self;
     self=pthread_self();
     pthread_mutex_lock(&m);
     done = 1;
     pthread_cond_signal(&c);
     pthread_mutex_unlock(&m);
     return NULL;
}
void *thr1(void *arg) {
     pthread_t self;
     self=pthread_self();
     pthread_mutex_lock(&m);
     while (done == 0)
     {
          pthread_cond_wait(&c, &m);
     }
     pthread_mutex_unlock(&m);
}
int main(int argc, char *argv[]) {
     pthread_t p,q,r;
     pthread_create(&q, NULL, thr1, NULL);
     sleep(2);
     pthread_create(&p, NULL, thr2, NULL);
     pthread_create(&r, NULL, thr2, NULL);
     pthread_join(p,NULL);
     pthread_join(q,NULL);
     pthread_join(r,NULL);
     return 0;
}

在这段代码中,我期望 thread1 等待条件变量完成。因此,线程 2 或线程 3 当任何一个启动并获得互斥锁并完成更改为 1 时。它必须向线程 1 发出信号,线程 1 正在等待,线程 1 将开始执行。

但是,我看到即使 thread1 正在等待条件变量 done=0 并且在来自 thread2 的信号之后,我为 thread2 方法创建的另一个线程获得了互斥锁。

我想知道我对输出的期望是否有任何问题。我正在尝试以类似的情况实现阻塞队列,其中可能有多个生产者和单个消费者。

谢谢, 普瓦南。

【问题讨论】:

    标签: c pthreads mutex wait


    【解决方案1】:

    你的期望是错误的。线程 1最终会醒来并获得互斥体,因为它已发出信号,但不能保证线程 3 不会首先到达那里。

    如果您不希望您的生产者线程在队列已满时“生产”(这里,您的队列长度为 1),那么您也需要让它们等待 - 您可以使用第二个条件变量那:

    int done = 0;
    pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t c_done = PTHREAD_COND_INITIALIZER;
    pthread_cond_t c_undone = PTHREAD_COND_INITIALIZER;
    
    void *thr2(void *arg)
    {
         pthread_mutex_lock(&m);
         /* wait for done to be zero */
         while (done != 0)
             pthread_cond_wait(&c_undone, &m);
         done = 1;
         pthread_cond_signal(&c_done);
         pthread_mutex_unlock(&m);
         return NULL;
    }
    
    void *thr1(void *arg)
    {
         pthread_mutex_lock(&m);
         while (done == 0)
         {
              pthread_cond_wait(&c_done, &m);
         }
         done = 0;
         pthread_cond_signal(&c_undone);
         pthread_mutex_unlock(&m);
    }
    

    【讨论】:

      【解决方案2】:

      来自官方POSIXpthread_cond_signal reference

      pthread_cond_signal() 函数应至少解除阻塞在指定条件变量 cond 上阻塞的线程之一

      如果多个线程在一个条件变量上被阻塞,调度策略将确定线程被解除阻塞的顺序

      这意味着你无法真正告诉哪个线程会被信号唤醒。如果您只想唤醒特定线程,则必须使用特定于该线程的条件变量。

      【讨论】:

      • 您好,感谢您的意见。我期待 pthread_cond_signal() 解除阻塞在条件变量上阻塞的线程。在我的例子中,只有一个线程等待条件变量。另一个由方法 thr2(比如说 thread3)创建的线程。我希望它在互斥锁从 thr2 (thread2) 释放后阻塞 mutex_lock,因为 thr1 等待条件变量。
      【解决方案3】:

      假设thr1 首先开始。 thr1 锁定互斥锁并等待条件,它在进入等待之前释放互斥锁mm 可用于线程 2 或线程 3。 thread2 或 thread3 之一将锁定互斥体并设置 done 并发出信号 thr1 并释放互斥体。但是thr1 不一定能够重新获取互斥锁m,因为另一个线程可能已经获取了互斥锁。

      即使thr1 等待的条件为真(done 由 thread2 或 thread3 设置为 1),它也不会返回,直到它可以再次锁定互斥锁。记住pthread_cond_wait() 在返回之前锁定互斥锁。这意味着thr1 仍在等待。

      另一点是thr1 应该在完成时返回NULL 或调用pthread_exit()。请注意,sleep 不是一个好的同步机制。

      【讨论】:

      • :感谢您的意见。但是,为什么 thr1 不一定能够在 thread2 释放互斥锁后重新获得互斥锁。我想,由于thread1已经在等待条件变量来获取互斥锁,它会在线程2发出信号后获取互斥锁。但是,我看到 thread3 获得了互斥锁。当我执行不同的时间时它会有所不同,互斥锁的获取是通过thread1或thread3。为什么 thread1 并不总是获得比 thread3 具有更高优先级的互斥锁(因为从 thread2 发出信号)?只是为了确保第一个线程在条件下等待,我包括了睡眠。
      • thr1 没有“更高”的优先级。它正在等待的事实并没有使其优先级更高。 pthread_cond_wait 必须重新获取互斥锁,如果另一个线程锁定了互斥锁,则它必须等待。
      • 好的。谢谢你。我以为在另一个线程锁 (thread3) 之前,thr1 会在从 thread2 发出信号后获取互斥锁。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-09
      • 2018-03-05
      • 1970-01-01
      • 1970-01-01
      • 2020-01-21
      • 2010-11-06
      • 1970-01-01
      相关资源
      最近更新 更多