首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >一个生产者,N个使用者并行工作,每个人做一个任务的~1/n

一个生产者,N个使用者并行工作,每个人做一个任务的~1/n
EN

Code Review用户
提问于 2013-12-29 08:35:43
回答 1查看 234关注 0票数 2

我不想知道错误检查(我很快就会补充)。相反,我想知道正确性、效率和简单性。

代码语言:javascript
运行
复制
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

#define  NTHREADS    7
#define  RUN_N_TIMES 37

pthread_cond_t      new_task_available  = PTHREAD_COND_INITIALIZER;
pthread_cond_t      task_complete       = PTHREAD_COND_INITIALIZER;
pthread_mutex_t     mutex               = PTHREAD_MUTEX_INITIALIZER;

volatile int producerCond           = 0;
volatile int consumerCond[NTHREADS] = {};    
volatile int no_more_tasks          = 0;
volatile int mini_tasks_complete    = - NTHREADS;

void do_work(unsigned int* current_level){
  /* Some work done */
  ++*current_level;
}

void *threadfunc(void *parm){
  volatile int* thread_cond;
  unsigned int level = 0;
  thread_cond = (volatile int*)parm;
  while(!no_more_tasks){
    pthread_mutex_lock(&mutex);
    mini_tasks_complete++;
    if(mini_tasks_complete > 0)
      printf("Thread %u has completed %u units of work.\nIt was #%d to complete it's task this round..\n", \
        (unsigned int)pthread_self(), level, mini_tasks_complete);
    if(mini_tasks_complete == NTHREADS){
      producerCond = 1;
      pthread_cond_signal(&task_complete);
    }
    *thread_cond = 0;
    while (!*thread_cond) {
      pthread_cond_wait(&new_task_available, &mutex);
    }
    pthread_mutex_unlock(&mutex);
    if(no_more_tasks){
      return NULL;
    } else {
      do_work(&level);
    }
  }
  return NULL;
}

void reset_cond(int val){
  int i;
  for (i=0; i<NTHREADS; ++i)
    consumerCond[i] = val;
}

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

  for(i=0; i < NTHREADS; ++i) {
    pthread_create(&threadid[i], NULL, threadfunc, (void*)&(consumerCond[i]));
  }

  while(mini_tasks_complete < 0){
    /* Do nothing */
  }

  printf("Waking up all waiting threads " "#RUN_N_TIMES" " times...\n");
  for(i = 0; i < RUN_N_TIMES; i++){
    pthread_mutex_lock(&mutex);
    mini_tasks_complete = 0;
    printf("New tasks available.\n");
    reset_cond(1);
    /* Wake them up */
    pthread_cond_broadcast(&new_task_available);
    producerCond = 0;
    while (!producerCond) {
      printf("Main waiting\n");
      /* Go to sleep */
      pthread_cond_wait(&task_complete, &mutex);
    }
    pthread_mutex_unlock(&mutex);
  }
  pthread_mutex_lock(&mutex);
  reset_cond(1);
  no_more_tasks = 1;
  printf("Go home everybody!\n");
  pthread_cond_broadcast(&new_task_available);
  printf("Wait for threads and cleanup...\n");
  pthread_mutex_unlock(&mutex);

  for (i=0; i<NTHREADS; ++i) {
    pthread_join(threadid[i], NULL);
  }

  pthread_cond_destroy(&new_task_available);
  pthread_cond_destroy(&task_complete);
  pthread_mutex_destroy(&mutex);

  printf("Main done\n");
  return 0;
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2013-12-31 13:36:20

这里有一些关于你的节目的评论。请注意,我不是线程专家。

首先,代码运行良好。我正在运行OSX,它干净地编译并正确执行(据我所知)。每次线程以相同的顺序醒来,这让我有点惊讶--换句话说,如果线程123456是第一个完成第一个作业的,那么它似乎是第一个完成每个后续作业的线程。这说明了更多关于线程实现的内容,而不是代码。

我在代码中遇到的问题是,尽管它看起来很有效,但它是专门针对当前问题编写的。确保所有线程间隔地连接在一起的屏障不是单独识别的,而是交织在控制代码中的。用于创建屏障的变量mini_tasks_complete被初始化为-NTHREADS,允许在初始屏障期间运行到零,然后从0循环到NTHREADS。这显然有效,但不优雅(我认为您会发现最初的障碍可以省略,并经过一点思考进入循环中)。

我更希望看到线程函数具有简单的形式:

代码语言:javascript
运行
复制
while (more_tasks) {
    barrier();
    work();
}

主线程具有以下一般形式:

代码语言:javascript
运行
复制
for (...) {
    prepare_work();
    barrier();
}

像这样的文字可以清楚地识别同步。此处的势垒函数也最好采用识别势垒的参数,而不使用全局函数。

我想你的平台,和我的平台一样,缺乏线程屏障。你可以写你自己的屏障函数。据我所读,障碍通常是基于一对条件变量和一对互斥。小符号学对此进行了讨论,有一个有用的Solaris实现可以用作模板。

一些琐事:

  • 我觉得while (more_tasks)while (!no_more_tasks)更符合逻辑
  • 不一致地使用camelCase
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/38264

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档