C++ 广播不';不要与障碍物打交道

C++ 广播不';不要与障碍物打交道,c++,c,multithreading,pthreads,parallel-processing,C++,C,Multithreading,Pthreads,Parallel Processing,我正在尝试使用pthreads实现一个基本的工作线程池。 这种情况下,我需要一个固定数量的工人,他们在我的项目期间一直生活 我永远不需要给单个线程发信号,但所有线程同时发信号,这就是为什么我想做单个广播的原因 在主程序继续之前,我需要等待所有线程完成,因此我决定在每个工作线程中使用barrier\u wait 问题是,如果我的线程调用barrier\u wait,广播就不能工作 下面是完整的示例和可编译代码。这只是针对广播的单触发器,在我的完整版本中,我将对如下内容进行因果循环 while(co

我正在尝试使用pthreads实现一个基本的工作线程池。 这种情况下,我需要一个固定数量的工人,他们在我的项目期间一直生活

我永远不需要给单个线程发信号,但所有线程同时发信号,这就是为什么我想做单个广播的原因

在主程序继续之前,我需要等待所有线程完成,因此我决定在每个工作线程中使用barrier\u wait

问题是,如果我的线程调用barrier\u wait,广播就不能工作

下面是完整的示例和可编译代码。这只是针对广播的单触发器,在我的完整版本中,我将对如下内容进行因果循环

while(conditionMet){
  1.prepare data
  2.signal threads using data
  3.post processing of thread results (because of barrier all threads finished)
  4.modify conditionMet if needed
}
谢谢

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void checkResults(char *str,int i){
  fprintf(stdout,"%s:%d\n",str,i);
}
void checkResults(char *str,size_t n,int i){
  fprintf(stdout,"%s[%lu]:%d\n",str,n,i);
}

/* For safe condition variable usage, must use a boolean predicate and  */
/* a mutex with the condition.                                          */
int                 conditionMet = 0;
pthread_cond_t      cond  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t     mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_barrier_t barr;

#define NTHREADS    3

void *threadfunc(void *parm)
{
  size_t i = (size_t) parm;
  int           rc;

  rc = pthread_mutex_lock(&mutex);
  checkResults("\tpthread_mutex_lock()",i, rc);

  while (0==conditionMet) {
    printf("\tThread blocked[%d]\n",(int)i);
    rc = pthread_cond_wait(&cond, &mutex);
    checkResults("\tpthread_cond_wait()",i, rc);
    checkResults("\tbefore barrier",i);
   rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out
    if(rc)
      fprintf(stdout,"problems waiting for baarr\n");
    checkResults("\tafter  barrier",i);
  }

  rc = pthread_mutex_unlock(&mutex);
  checkResults("\tpthread_mutex_lock()",i, rc);
  return NULL;
}

int main(int argc, char **argv)
{
  int                   rc=0;
  int                   i;
  pthread_t             threadid[NTHREADS];

  if(pthread_barrier_init(&barr, NULL,NTHREADS))
    {
      printf("Could not create a barrier\n");
    }



  printf("Enter Testcase - %s\n", argv[0]);

  printf("Create %d threads\n", NTHREADS);
  for(i=0; i<NTHREADS; ++i) {
    rc = pthread_create(&threadid[i], NULL, threadfunc,(void *) i);
    if(rc)
      checkResults("pthread_create()", rc);
  }

  sleep(5);  /* Sleep isn't a very robust way to serialize threads */
  rc = pthread_mutex_lock(&mutex);
  checkResults("pthread_mutex_lock()", rc);

  /* The condition has occured. Set the flag and wake up any waiters */
  conditionMet = 1;
  printf("\nWake up all waiters...\n");
  rc = pthread_cond_broadcast(&cond);
  checkResults("pthread_cond_broadcast()", rc);

  rc = pthread_mutex_unlock(&mutex);
  checkResults("pthread_mutex_unlock()", rc);

  printf("Wait for threads and cleanup\n");
  for (i=0; i<NTHREADS; ++i) {
    rc = pthread_join(threadid[i], NULL);
    checkResults("pthread_join()", rc);
  }
  pthread_cond_destroy(&cond);
  pthread_mutex_destroy(&mutex);

  printf("Main completed\n");
  return 0;
}
#包括
#包括
#包括
无效检查结果(字符*str,整数i){
fprintf(stdout,“%s:%d\n”,str,i);
}
无效检查结果(字符*str,大小\u t n,整数i){
fprintf(stdout,“%s[%lu]:%d\n”,str,n,i);
}
/*为了安全使用条件变量,必须使用布尔谓词和*/
/*具有该条件的互斥体*/
int conditionMet=0;
pthread_cond_t cond=pthread_cond_初始值设定项;
pthread\u mutex\u t mutex=pthread\u mutex\u初始值设定项;
pthread_barr_t barr;
#定义第3行
void*threadfunc(void*parm)
{
大小i=(大小)parm;
int rc;
rc=pthread\u mutex\u lock(&mutex);
检查结果(“\tpthread\u mutex\u lock()”,i,rc);
while(0==条件满足){
printf(“\t线程阻塞[%d]\n”,(int)i);
rc=pthread\u cond\u wait(&cond,&mutex);
检查结果(“\tpthread\u cond\u wait()”,i,rc);
检查结果(“\t屏障前”,i);
rc=pthread\u barrier\u wait(&barr);//如果将其注释掉,则广播工作
if(rc)
fprintf(标准输出,“等待baarr的问题”);
检查结果(“\t屏障后”,i);
}
rc=pthread\u mutex\u unlock(&mutex);
检查结果(“\tpthread\u mutex\u lock()”,i,rc);
返回NULL;
}
int main(int argc,字符**argv)
{
int rc=0;
int i;
pthread_t threadid[NTHREADS];
if(pthread\u barrier\u init(&barr,NULL,NTHREADS))
{
printf(“无法创建屏障\n”);
}
printf(“输入Testcase-%s\n”,argv[0]);
printf(“创建%d个线程\n”,n个线程);

对于(i=0;i线程函数将在接收到信号后立即锁定
互斥体
。因此,只有一个线程函数将在屏障上等待(在
互斥体
仍被锁定的情况下),屏障标准将永远无法满足

为了使用屏障,您应该重新设计应用程序的逻辑。
互斥体必须在等待屏障之前立即解锁。
pthread\u cond\u wait()
在代码中使用,应用程序中只有一个线程处于活动状态,这就完全消除了多线程的需要

编辑:

我想详细解释一下最后一句话。假设我们修改线程函数如下:

while (0==conditionMet) {     
    printf("\tThread blocked[%d]\n",(int)i);     
    rc = pthread_cond_wait(&cond, &mutex);     
    checkResults("\tpthread_cond_wait()",i, rc);     
    checkResults("\tbefore barrier",i);

    pthread_mutex_unlock(&mutex); //added    

    rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out     
    if(rc)
        fprintf(stdout,"problems waiting for baarr\n");     
    checkResults("\tafter  barrier",i);   
}
void *threadfunc(void *parm)
{
/*...*/
struct ThreadRuntimeData {
} rtd;
while (0==conditionMet) {     
    printf("\tThread blocked[%d]\n",(int)i);     
    rc = pthread_cond_wait(&cond, &mutex);     
    checkResults("\tpthread_cond_wait()",i, rc);

    GetWorkData(&rtd); //Gets some data from critical section and places it in rtd
    pthread_mutex_unlock(&mutex);

    ProcessingOfData(&rtd); //here we do the thread's job 
    //without the modification of global data; this may take a while

    pthread_mutex_lock(&mutex);
    PublishProcessedData(&rtd); //Here we modify some global data 
    //with the results of thread's work. 
    //Other threads may do the same, so we had to enter critical section again
    pthread_mutex_unlock(&mutex);   
    checkResults("\tbefore barrier",i);
    rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out     
    if(rc)
        fprintf(stdout,"problems waiting for baarr\n");     
    checkResults("\tafter  barrier",i);   
}
/*...*/
}
通过这种方式,我们可以在只有一个线程能够到达导致
互斥锁
锁定的屏障时消除死锁。但在给定的时间内,仍然只有一个线程在关键部分运行:当它是
pthread\u cond\u wait()时
返回被锁定的
互斥锁,它将保持锁定状态,直到线程函数达到_unlock();_wait();对。只有在这之后,下一个线程才能运行并达到其屏障。清洗、冲洗、重复

OP prolly想要的是让线程函数同时运行(为什么其他人会想要线程池?)

while (0==conditionMet) {     
    printf("\tThread blocked[%d]\n",(int)i);     
    rc = pthread_cond_wait(&cond, &mutex);     
    checkResults("\tpthread_cond_wait()",i, rc);     
    checkResults("\tbefore barrier",i);

    pthread_mutex_unlock(&mutex); //added    

    rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out     
    if(rc)
        fprintf(stdout,"problems waiting for baarr\n");     
    checkResults("\tafter  barrier",i);   
}
void *threadfunc(void *parm)
{
/*...*/
struct ThreadRuntimeData {
} rtd;
while (0==conditionMet) {     
    printf("\tThread blocked[%d]\n",(int)i);     
    rc = pthread_cond_wait(&cond, &mutex);     
    checkResults("\tpthread_cond_wait()",i, rc);

    GetWorkData(&rtd); //Gets some data from critical section and places it in rtd
    pthread_mutex_unlock(&mutex);

    ProcessingOfData(&rtd); //here we do the thread's job 
    //without the modification of global data; this may take a while

    pthread_mutex_lock(&mutex);
    PublishProcessedData(&rtd); //Here we modify some global data 
    //with the results of thread's work. 
    //Other threads may do the same, so we had to enter critical section again
    pthread_mutex_unlock(&mutex);   
    checkResults("\tbefore barrier",i);
    rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out     
    if(rc)
        fprintf(stdout,"problems waiting for baarr\n");     
    checkResults("\tafter  barrier",i);   
}
/*...*/
}
当然,这只是一个草图。线程函数的优化设计取决于OP希望线程做什么


作为旁注,检查
pthread\u barrier\u wait()的代码
返回结果必须考虑
PTHREAD\u BARRIER\u SERIAL\u THREAD
返回。另外,将
conditionMet
声明为
volatile

更安全,线程函数在接收到信号后会立即锁定
互斥体。因此,只有一个线程函数会等待BARRIER(在
互斥锁
仍然锁定的情况下)并且永远不会满足屏障标准

为了使用屏障,您应该重新设计应用程序的逻辑。
互斥体必须在等待屏障之前立即解锁。
pthread\u cond\u wait()
在代码中使用,应用程序中只有一个线程处于活动状态,这就完全消除了多线程的需要

编辑:

我想详细解释一下最后一句话。假设我们修改线程函数如下:

while (0==conditionMet) {     
    printf("\tThread blocked[%d]\n",(int)i);     
    rc = pthread_cond_wait(&cond, &mutex);     
    checkResults("\tpthread_cond_wait()",i, rc);     
    checkResults("\tbefore barrier",i);

    pthread_mutex_unlock(&mutex); //added    

    rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out     
    if(rc)
        fprintf(stdout,"problems waiting for baarr\n");     
    checkResults("\tafter  barrier",i);   
}
void *threadfunc(void *parm)
{
/*...*/
struct ThreadRuntimeData {
} rtd;
while (0==conditionMet) {     
    printf("\tThread blocked[%d]\n",(int)i);     
    rc = pthread_cond_wait(&cond, &mutex);     
    checkResults("\tpthread_cond_wait()",i, rc);

    GetWorkData(&rtd); //Gets some data from critical section and places it in rtd
    pthread_mutex_unlock(&mutex);

    ProcessingOfData(&rtd); //here we do the thread's job 
    //without the modification of global data; this may take a while

    pthread_mutex_lock(&mutex);
    PublishProcessedData(&rtd); //Here we modify some global data 
    //with the results of thread's work. 
    //Other threads may do the same, so we had to enter critical section again
    pthread_mutex_unlock(&mutex);   
    checkResults("\tbefore barrier",i);
    rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out     
    if(rc)
        fprintf(stdout,"problems waiting for baarr\n");     
    checkResults("\tafter  barrier",i);   
}
/*...*/
}
通过这种方式,我们可以在只有一个线程能够到达导致
互斥锁
锁定的屏障时消除死锁。但在给定的时间内,仍然只有一个线程在关键部分运行:当它是
pthread\u cond\u wait()时
返回被锁定的
互斥锁,它将保持锁定状态,直到线程函数达到_unlock();_wait();对。只有在这之后,下一个线程才能运行并达到其屏障。清洗、冲洗、重复

OP prolly想要的是让线程函数同时运行(为什么其他人会想要线程池?)

while (0==conditionMet) {     
    printf("\tThread blocked[%d]\n",(int)i);     
    rc = pthread_cond_wait(&cond, &mutex);     
    checkResults("\tpthread_cond_wait()",i, rc);     
    checkResults("\tbefore barrier",i);

    pthread_mutex_unlock(&mutex); //added    

    rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out     
    if(rc)
        fprintf(stdout,"problems waiting for baarr\n");     
    checkResults("\tafter  barrier",i);   
}
void *threadfunc(void *parm)
{
/*...*/
struct ThreadRuntimeData {
} rtd;
while (0==conditionMet) {     
    printf("\tThread blocked[%d]\n",(int)i);     
    rc = pthread_cond_wait(&cond, &mutex);     
    checkResults("\tpthread_cond_wait()",i, rc);

    GetWorkData(&rtd); //Gets some data from critical section and places it in rtd
    pthread_mutex_unlock(&mutex);

    ProcessingOfData(&rtd); //here we do the thread's job 
    //without the modification of global data; this may take a while

    pthread_mutex_lock(&mutex);
    PublishProcessedData(&rtd); //Here we modify some global data 
    //with the results of thread's work. 
    //Other threads may do the same, so we had to enter critical section again
    pthread_mutex_unlock(&mutex);   
    checkResults("\tbefore barrier",i);
    rc = pthread_barrier_wait(&barr);//broadcast works if this is commented out     
    if(rc)
        fprintf(stdout,"problems waiting for baarr\n");     
    checkResults("\tafter  barrier",i);   
}
/*...*/
}
当然,这只是一个草图。线程函数的优化设计取决于OP希望线程做什么


作为旁注,检查
pthread\u barrier\u wait()的代码
返回结果必须考虑
PTHREAD\u BARRIER\u SERIAL\u THREAD
返回。另外,将
conditionMet
声明为
volatile
更安全,因为问题不清楚输入数据是什么,以及它们与线程和结果的关系如何.我看不出发布的代码,因为我看不出实际工作应该在哪里完成

<