Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何确保线程被阻塞?_C_Multithreading_Synchronization_Pthreads - Fatal编程技术网

C 如何确保线程被阻塞?

C 如何确保线程被阻塞?,c,multithreading,synchronization,pthreads,C,Multithreading,Synchronization,Pthreads,我有一个多线程C基准测试,可以描述如下: Thread 1 Thread 2 Thread 3 Control thread while(1) while(1) while(1) while(1) | | | | | | | | | |

我有一个多线程C基准测试,可以描述如下:

Thread 1   Thread 2   Thread 3       Control thread

while(1)   while(1)    while(1)       while(1)
   |          |          |             
   |          |          |                |             
   |          |          |            every one second: 
   |          |          |               wait for other threads to be blocked
   |          |          |               do something with S values
   |          |          |                |             
   |          |          |                |             
 write S1    write S2   write S3          |
   |          |          |                |          
   |          |          |                |
 barrier     barrier   barrier         barrier
我的问题涉及上图中的
等待其他线程被阻塞
语句。目前,我采用以下解决方案来实现它:

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <inttypes.h>

#define NB_THREADS 11

pthread_barrier_t b;
uint8_t blocked_flags[NB_THREADS] = {0};
pthread_mutex_t blocked_flags_mutexes[NB_THREADS];
uint64_t states[NB_THREADS] = {0};

uint64_t time_diff_get(struct timespec *start, struct timespec *end) {
  uint64_t end_ns = end->tv_sec * 1E9 + end->tv_nsec;
  uint64_t start_ns = start->tv_sec * 1E9 + start->tv_nsec;
  uint64_t res = end_ns - start_ns;
  return res;
}

static void *worker_thread(void *arg) {
  uint8_t id = *((uint8_t *)arg);
  int a =  0;
  while(1) {
    for (int i = 0; i < 1000; i++) {
      a++;
    }
    states[id]++;
    pthread_mutex_lock(&blocked_flags_mutexes[id]);
    blocked_flags[id] = 1;
    pthread_mutex_unlock(&blocked_flags_mutexes[id]);
    pthread_barrier_wait(&b);
    pthread_mutex_lock(&blocked_flags_mutexes[id]);
    blocked_flags[id] = 0;
    pthread_mutex_unlock(&blocked_flags_mutexes[id]);
  }
  printf ("a = %d\n", a);
  return NULL;
}

static void *control_thread() {

  struct timespec last_time;
  clock_gettime(CLOCK_REALTIME, &last_time);

  while(1) {

    struct timespec time;
    clock_gettime(CLOCK_REALTIME, &time);
    if (time_diff_get(&last_time, &time) >= 1E9) {

      // Wait for all threads to be blocked
      for (int i = 0; i < NB_THREADS; i++) {
        while (1) {
          pthread_mutex_lock(&blocked_flags_mutexes[i]);
          if (blocked_flags[i] == 1) {
            pthread_mutex_unlock(&blocked_flags_mutexes[i]);
            break;
          }
          pthread_mutex_unlock(&blocked_flags_mutexes[i]);
        }
      }
      for (int i = 0; i < NB_THREADS; i++) {
        pthread_mutex_lock(&blocked_flags_mutexes[i]);
        if (blocked_flags[i] == 0) {
          printf("How could I avoid to be there ??\n");
          exit(-1);
        }
        pthread_mutex_unlock(&blocked_flags_mutexes[i]);
      }

      // Do some intersting stuff here with states array
      // .....
      // .....

      // Save last time
      clock_gettime(CLOCK_REALTIME, &last_time);
    }

    pthread_barrier_wait(&b);
  }
  return NULL;
}

int main() {

  // Init barrier
  pthread_barrier_init(&b, NULL, NB_THREADS + 1);

  // Create worker threads
  pthread_t threads[NB_THREADS];
  uint8_t ids[NB_THREADS];
  for (int i = 0; i < NB_THREADS; i++) {
    ids[i] = i;
    pthread_mutex_init(&blocked_flags_mutexes[i], NULL);
  }
  for (int i = 0; i < NB_THREADS; i++) {
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    cpu_set_t cpu_set;
    CPU_ZERO(&cpu_set);
    CPU_SET(i + 1, &cpu_set);
    pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpu_set);
    pthread_create(&threads[i], &attr, worker_thread, &ids[i]);
  }

  // Create control thread
  pthread_t ctrl_thread;
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  cpu_set_t cpu_set;
  CPU_ZERO(&cpu_set);
  CPU_SET(0, &cpu_set);
  pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpu_set);
  pthread_create(&ctrl_thread, &attr, control_thread, NULL);

  // Join on worker threads
  for (int i = 0; i < NB_THREADS; i++) {
    pthread_join(threads[i], NULL);
  }

  return 0;
}
\ifndef\u GNU\u源代码
#定义GNU源
#恩迪夫
#包括
#包括
#包括
#包括
#包括
#包括
#定义NB_线程11
pthread_barrier_t b;
uint8_t blocked_标志[NB_线程]={0};
pthread_mutex_t blocked_flags_mutex[NB_THREADS];
uint64_t状态[NB_线程]={0};
uint64时间差异获取(结构时间域*开始,结构时间域*结束){
uint64\u t end\u ns=end->tv\u sec*1E9+end->tv\u nsec;
uint64\u t start\u ns=start->tv\u sec*1E9+start->tv\u nsec;
uint64\u t res=结束\u ns-开始\u ns;
返回res;
}
静态void*辅助线程(void*arg){
uint8_t id=*((uint8_t*)arg);
int a=0;
而(1){
对于(int i=0;i<1000;i++){
a++;
}
状态[id]++;
pthread_mutex_lock(&blocked_flags_mutex[id]);
阻塞的_标志[id]=1;
pthread_mutex_unlock(&blocked_flags_mutex[id]);
pthread\u barrier\u wait(&b);
pthread_mutex_lock(&blocked_flags_mutex[id]);
阻塞的_标志[id]=0;
pthread_mutex_unlock(&blocked_flags_mutex[id]);
}
printf(“a=%d\n”,a);
返回NULL;
}
静态void*控制线程(){
结构timespec最后一次;
时钟获取时间(时钟实时和上次时间);
而(1){
结构时间段时间;
时钟获取时间(时钟实时和时间);
如果(时间差获取(&上次时间和时间)>=1E9){
//等待所有线程被阻塞
对于(int i=0;i
但是在12核Intel平台上运行这个用
gcc-O0
编译的基准测试清楚地表明,我在某个地方遇到了“竞争”问题,因为进程总是在几秒钟后带着消息退出。我怎样才能解决这个问题


注意:在其他问题之后,我想使用自定义屏障,但我需要继续使用pthread_屏障,而不是在互斥和cond变量上重新实现屏障。

而不是为每个工作线程保留一个标志,您可以对单个计数器进行互斥保护,每个工作线程可以在即将阻塞计数器时增加该计数器,并在屏障释放计数器后减少该计数器。这将避免您等待第一个线程被阻塞,然后是第二个线程,然后是第三个线程,等等

我不知道你的控制线程在哪里退出(除了在意外的情况下),主线程似乎没有等待它

也许您还希望在工作线程之前创建控制线程


也许您还希望同步工作线程和控制线程,让它们在释放之前等待屏障并开始实际工作

我认为发生的事情可能是:

  • 在control_thread()中第一次执行
    while(1)
    time_diff_get(&last_time,&time)
    返回一个值<1E9,因此线程直接运行到屏障中
  • 现在所有的工作线程最终都会遇到障碍
  • 发生这种情况后,
    control\u thread()
    第二次执行它的循环,并立即检查
    blocked\u标志[i]
  • 如果至少有一个线程在该线程重置其标志之前发生这种情况,那么您将具有预期的行为

很抱歉,我目前无法提供解决方案,但如果我正确理解该问题,则是解决方案的良好开端

您的代码有一个明显的争用条件。当您的线程被屏障等待解除阻塞时,它们会将标志重置为零。在他们这么做之前,他们的旗帜在一段时间内仍然是1。控制线程可以观察到这个陈旧的值1,并认为相应的线程已经准备好阻塞,而实际上该线程刚刚要清除标志,刚刚走出障碍等待:

// worker thread
pthread_barrier_wait(&b);
// No longer blocked, but blocked_flags[id] is still 1.
// At this point, the control thread grabs the mutex, and observes the 1 value
// The mistake is thinking that 1 means "I'm about to block"; it actually
// means, "I'm either about to block on the barrier, or have just finished".
pthread_mutex_lock(&blocked_flags_mutexes[id]);
blocked_flags[id] = 0;
pthread_mutex_unlock(&blocked_flags_mutexes[id]);
这种竞争条件有时足以愚弄控制线程,使其知道所有人都被阻止,从而通过其第一个循环。然后它进入第二个循环,在那里它发现n
while(1)   while(1)    while(1)       
   |          |          |             
   |          |          |          
   |          |          | 
   |          |          |   <---- WRITE PHASE  
   |          |          |  
   |          |          |             
   |          |          |                 
 write S1    write S2   write S3
   |          |          |           
   |          |          |      
 barrier     barrier   barrier 
   |          |          |        
   |          |          |     <--- CHECK PHASE
   |          |          |           
   |          |     serial thread!   
   |          |          |           
   |          |       next second?-- YES -> do something with S values!
   |          |          |  NO        |
   |          |          |            |
   |          |          +------------+ 
   |          |          | 
 barrier     barrier   barrier
   |          |          | 
   |          |          | 

back to top, next WRITE PHASE.