定期触发pthread工作线程并等待完成

问题描述 投票:0回答:1

我想在原始进程的控制下创建一组 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”并让它们全部完成,以便我可以处理它们的结果并安全地更改全局变量为下一个周期。

c linux pthreads
1个回答
0
投票

你可以使用条件变量。

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.
© www.soinside.com 2019 - 2024. All rights reserved.