我想在原始进程的控制下创建一组 N 个 pthreads。我想像这个伪代码一样控制它们:
create_n_threads();
While(1) {
main task modifies a global variable "phase" to control the type of work
trigger the N threads to wake up and do work based on the global "phase" variable
wait until all threads have completed their tasks
main task does meta-calculation on the partial results of all the workers
}
我尝试过pthread_barrier_wait()。它可以很好地触发计算周期,但它无法让我知道每个任务何时完成。我如何知道所有线程何时完成,以便我可以安全地对结果进行元计算?我不想使用 pthread_join,因为这些工作周期将处于紧密循环中,并且我不希望在每个周期上杀死和重新创建任务的开销。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h> // for sleep()
#define NTHREADS 4
pthread_barrier_t b;
typedef struct threadargs {
int id; // thread ID 0-\>N
int phase; // either 0 or non zero to set blk/red phase
} THREADARGS;
int phase=0;
int cycle=0;
// worker function
// gets called with a pointer to THREADARGS structure
// which tells worker their id, starting, ending column to relax, and the red/black phase
void \*thread_func(void \*x)
{
int tid; // thread id
int *retval = (int *) malloc(sizeof(int)); // so it persists across thread death
tid = ((THREADARGS *) x)->id;
while(1) { // wait to be triggered
printf("%d: %d %d\n", cycle, tid, phase);
pthread_barrier_wait(&b);
}
*retval = 2*tid;
pthread_exit((void *)retval);
}
int main(int argc, char \*argv\[\])
{
pthread_t threadids\[NTHREADS\]; // store os thread ids
THREADARGS thread_args\[NTHREADS\]; // arguments to thread
int rc, i;
// initialize the multiprocess barrier
pthread_barrier_init(&b, NULL, NTHREADS+1);
/* spawn the threads */
for (i = 0; i < NTHREADS; ++i) {
thread_args[i].id = i;
printf("spawning thread %d\n", i);
if((rc=pthread_create(&threadids[i], NULL, thread_func, (void *) &thread_args[i]))!=0) {
fprintf(stderr, "cannot create thread %d\n",i);
exit(8);
};
}
for (i=0; i<10; i++) { // do ten iterations
printf("cycle %d\n", i);
phase=(phase+1)%3;
cycle++;
pthread_barrier_wait(&b); // trigger all the workers and wait for all to complete
}
exit(2); // just kill everything
}
此示例产生如下输出:
!) pthread
spawning thread 0
spawning thread 1
spawning thread 2
spawning thread 3
0: 0 0
0: 1 0
cycle 0
1: 2 1
1: 3 1
1: 3 1
1: 1 1
1: 2 1
1: 0 1
cycle 1
cycle 2
3: 1 0
3: 3 0
3: 2 0
3: 0 0
3: 0 0
3: 2 0
3: 3 0
cycle 3
3: 1 0
4: 1 1
4: 2 1
4: 0 1
4: 3 1
您可以看到,一些工作进程每个周期运行多次,并且“阶段”变量在每个周期之间无法正确计数。我想要的是这样的:
cycle 1
1: 0 0
1: 1 0
1: 2 0
1: 3 0
cycle 2
2: 0 1
2: 1 1
2: 2 1
2: 2 1
cycle 3
3: 0 2
...
当然,每个任务的打印语句都会被打乱,但我想触发所有 4 个 pthread 来执行任务“0,1,2”并让它们全部完成,以便我可以处理它们的结果并安全地更改全局变量为下一个周期。
你可以使用条件变量。
int done = 0;
int work = 0;
int working = 0;
int waiting = n;
工人:
while ( 1 ) {
pthread_mutex_lock( &mutex );
while ( !work && !done )
pthread_cond_wait( &cond, &mutex );
if ( !done ) {
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );
return;
}
--work
--waiting;
++working;
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );
// Do work.
pthread_mutex_lock( &mutex );
--working;
++waiting;
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );
}
主要:
pthread_mutex_lock( &mutex );
while (1) {
work += n;
pthread_cond_signal( &cond );
while ( work || working )
pthread_cond_wait( &cond, &mutex );
// Process result.
}
done = 1;
pthread_cond_signal( &cond );
pthread_mutex_unlock( &mutex );
// Join worker threads here.