我不想知道错误检查(我很快就会补充)。相反,我想知道正确性、效率和简单性。
#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;
}发布于 2013-12-31 13:36:20
这里有一些关于你的节目的评论。请注意,我不是线程专家。
首先,代码运行良好。我正在运行OSX,它干净地编译并正确执行(据我所知)。每次线程以相同的顺序醒来,这让我有点惊讶--换句话说,如果线程123456是第一个完成第一个作业的,那么它似乎是第一个完成每个后续作业的线程。这说明了更多关于线程实现的内容,而不是代码。
我在代码中遇到的问题是,尽管它看起来很有效,但它是专门针对当前问题编写的。确保所有线程间隔地连接在一起的屏障不是单独识别的,而是交织在控制代码中的。用于创建屏障的变量mini_tasks_complete被初始化为-NTHREADS,允许在初始屏障期间运行到零,然后从0循环到NTHREADS。这显然有效,但不优雅(我认为您会发现最初的障碍可以省略,并经过一点思考进入循环中)。
我更希望看到线程函数具有简单的形式:
while (more_tasks) {
barrier();
work();
}主线程具有以下一般形式:
for (...) {
prepare_work();
barrier();
}像这样的文字可以清楚地识别同步。此处的势垒函数也最好采用识别势垒的参数,而不使用全局函数。
我想你的平台,和我的平台一样,缺乏线程屏障。你可以写你自己的屏障函数。据我所读,障碍通常是基于一对条件变量和一对互斥。小符号学对此进行了讨论,有一个有用的Solaris实现可以用作模板。
一些琐事:
while (more_tasks)比while (!no_more_tasks)更符合逻辑https://codereview.stackexchange.com/questions/38264
复制相似问题