确保线程在广播之前创建并等待

时间:2011-12-13 21:15:39

标签: c++ c multithreading thread-safety pthreads

我有10个线程应该等待信号。 到目前为止,我只是完成了'sleep(3)',并且一直运行良好,但有一种更安全的方法可以确保所有线程都已创建并且确实在等待。

我在关键区域中进行了以下构造,在等待之前,增加一个计数器,告诉有多少线程在等待。但是后来我必须有一个额外的互斥量并且有条件地向主信号发送所有线程都被创建,它看起来过于复杂。

我错过了一些基本的线程设计模式吗?

由于 编辑:固定类型

编辑:澄清以下信息

在这种情况下屏障不起作用,因为我不想让我的线程等到所有线程都准备就绪。这已经发生在'cond_wait'。

当所有线程都准备好并等待时,我很想知道main函数。

//mutex and conditional to signal from main to threads to do work
mutex_t mutex_for_cond;
condt_t cond;

//mutex and conditional to signal back from thread to main that threads are ready
mutex_t mutex_for_back_cond;
condt_t back_cond;

int nThreads=0;//threadsafe by using mutex_for_cond

void *thread(){
    mutex_lock(mutex_for_cond);
    nThreads++;
    if(nThreads==10){
      mutex_lock(mutex_for_back_cond)
      cond_signal(back_cond);
      mutex_unlock(mutex_for_back_cond)
    }while(1){
      cond_wait(cond,mutext_for_cond);
      if(spurious)
        continue; 
      else
        break;
    }
    mutex_unlock(mutex_for_cond);
    //do work on non critical region data
}

int main(){
for(int i=0;i<10)
   create_threads;

while(1){
   mutex_lock(mutex_for_back_cond);
   cond_wait(back_cond,mutex_for_back_cond);
   mutex_unlock(mutex_for_back_cond);
   mutex_lock(mutex_for_cond);
   if(nThreads==10){
     break;
   }else{
     //spurious wakeup 
     mutex_unlock(mutex_for_cond);
   }
}
//now all threads are waiting
//mutex_for_cond is still locked so broadcast
cond_broadcast(cond);//was type here


}

3 个答案:

答案 0 :(得分:3)

  

我错过了一些基本的线程设计模式吗?

是。对于每种情况,都应该有一个受随附的互斥锁保护的变量。只有条件变量上的信号才能指示此变量的变化。

您在循环中检查变量,等待条件:

mutex_lock(mutex_for_back_cond);
while ( ready_threads < 10 )
   cond_wait(back_cond,mutex_for_back_cond);
mutex_unlock( mutex_for_back_cond );

此外,您正在尝试构建的是一个线程障碍。它通常在线程库中预先实现,如pthread_barrier_wait

答案 1 :(得分:2)

敏感线程API有一个barrier构造,正是这样做的。

例如,对于boost::thread,您可以创建一个这样的屏障:

boost::barrier bar(10); // a barrier for 10 threads

然后每个线程都会在屏障上等待:

bar.wait();

屏障等待直到指定数量的线程等待它,然后立即释放所有线程。换句话说,一旦创建了所有十个线程并准备就绪,它将允许所有线程继续进行。

这是一种简单而明智的方式。没有屏障结构的线程API要求你以艰难的方式去做,这与你现在所做的不同。

答案 2 :(得分:0)

您应该将包含“事件状态”的某个变量与条件变量相关联。主线程在发出广播之前恰当地设置事件状态变量。对事件感兴趣的线程检查事件状态变量,无论它们是否在条件变量上被阻塞。

使用这种模式,主线程不需要知道线程的精确状态 - 它只是在需要然后广播条件时设置事件。任何等待的线程都将被解除阻塞,并且任何未等待的线程将永远不会阻塞条件变量,因为它们会在等待条件之前注意到事件已经发生。类似下面的伪代码:

//mutex and conditional to signal from main to threads to do work
pthread_mutex_t mutex_for_cond;
pthread_cond_t cond;
int event_occurred = 0;

void *thread() 
{
    pthread_mutex_lock(&mutex_for_cond);
    while (!event_occurred) {
            pthread_cond_wait( &cond, &mutex_for_cond);
    }
    pthread_mutex_unlock(&mutex_for_cond);

    //do work on non critical region data
}

int main()
{
    pthread_mutex_init(&mutex_for_cond, ...);
    pthread_cond_init(&cond, ...);

    for(int i=0;i<10)
        create_threads(...);

    // do whatever needs to done to set up the work for the threads

    // now let the threads know they can do their work (whether or not
    //  they've gotten to the "wait point" yet)
    pthread_mutex_lock(&mutex_for_cond);
    event_occured = 1;
    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&mutex_for_cond);
}