计数器值使用pthread

时间:2015-12-31 12:34:52

标签: c multithreading thread-safety pthreads

我正在实现一个完整的动态Receivers-Reader程序:我有许多Receiver Threads(由用户决定),每个都连接到一个特定的客户端,然后一个读取线程按时间顺序从Receivers的输出队列中读取并在.log文件中打印数据。

所以我连接一个客户端,创建了第一个Receiver Thread。我无法理解为什么在阅读元素之后突然在阅读线程中,第二个接收器(尚未创建)的计数器在没有任何指令的情况下增加1。以下是涉及的代码部分:

接收线程:

printf("Receiver ID: %d, counter: %d\n", rec_arg->receiver_ID, *(rec_arg->counter));
rec_arg->joint_queue[*(rec_arg->tail)] = rec_meas;

pthread_mutex_lock(rec_arg->mtx);
*(rec_arg->tail) = (*(rec_arg->tail) + 1) % QUEUE_SIZE;
(*(rec_arg->counter))++;
pthread_mutex_unlock(rec_arg->mtx);
printf("Receiver ID: %d, counter: %d\n", rec_arg->receiver_ID, *(rec_arg->counter));
printf("Receiver: tail: %d, joint_queue: %p\n", *(rec_arg->tail), (void*) rec_arg->joint_queue);
pthread_cond_signal(rec_arg->notEmpty); 

阅读主题:

  pthread_mutex_lock(read_arg->queue_mtx[i]);
  (*(read_arg->counters[i]))--;
  printf("Reading Thread: counter[%d]: %d\n", i, *(read_arg->counters[i]));

  if( writetofile(filename, &read_meas) == 0)
       fprintf(stderr,"Reading Thread: writetofile() failed\n");

  *(read_arg->OkRead[i]) = 0;
  *(read_arg->OkRead[(i+1) % read_arg->n_joints]) = 1;
  pthread_mutex_unlock(read_arg->queue_mtx[i]);
  printf("Reading Thread: OkRead[%d]: %d\n", (i+1) % read_arg->n_joints, *(read_arg->OkRead[(i+1) % read_arg->n_joints]));

  printf("Reading Thread: counter[%d]: %d\n", (i+1) % read_arg->n_joints, *(read_arg->counters[(i+1) % read_arg->n_joints])); 

输出显示:

Reading Thread: counter[0]: 0  
Reading Thread: OkRead[1]: 1  
Reading Thread: counter[1]: 1  
Reading Thread: counter[1]: 1  

更确切地说,可以创建两个线程,当第一个客户端连接时,它会发送数据。接收器线程将数据放入其队列中,读取线程将数据保存在.log文件中,递减计数器[0],给予读取第二个接收器(OkRead[1] = 1)的权限,然后在没有任何指示的情况下{{{ 1}}显示增量:counter[1]

希望能够理解这个问题,谢谢你的关注。

2 个答案:

答案 0 :(得分:1)

阅读线程中,您是外部的队列计数器互斥锁。 这意味着另一个线程可以在此期间修改OkRead[]counters[]。这是data raceundefined behaviour

在读取值后,将呼叫移至pthread_mutex_unlock()

  printf("Reading Thread: OkRead[%d]: %d\n", (i+1) % read_arg->n_joints, *(read_arg->OkRead[(i+1) % read_arg->n_joints]));

  printf("Reading Thread: counter[%d]: %d\n", (i+1) % read_arg->n_joints, *(read_arg->counters[(i+1) % read_arg->n_joints]));

  pthread_mutex_unlock(read_arg->queue_mtx[i]);

或者使用在释放互斥锁之前存储值的线程局部变量。如,

  ...
  int joints = (i+1) % read_arg->n_joints;
  int okread = *(read_arg->OkRead[(i+1) % read_arg->n_joints]);
  int counters = *(read_arg->counters[(i+1) % read_arg->n_joints]);

  pthread_mutex_unlock(read_arg->queue_mtx[i]);

  printf("Reading Thread: OkRead[%d]: %d\n", joints, okread);   
  printf("Reading Thread: counter[%d]: %d\n", (i+1) % read_arg->n_joints, counters ); 

答案 1 :(得分:1)

我明白了。每个参数,多个线程需要访问,必须在main()中声明为指针,初始化函数需要他的地址。

以前,我的代码就像:

主要():

  int *counter;
  info_init(&counter, n_elem);

  read_arg->counters = &counter;

void info_init(int ** info,int n_elem):

  *info = malloc(n_joints*sizeof(int*));
  if(*info == NULL) 
  printf("queues_init: malloc failed, errno: %d, meaning: %s\n", errno, strerror(errno));

 int i;
 for(i=0; i<n_joints; i++) {
 info[i] = (int*) malloc(sizeof(int));
  *(info[i]) = 0;
 }

 return;
 }

我用以下方法解决了问题:

主要():

 int **counter;
 info_init(&counter, n_elem);

 read_arg->counters = counter; 

void info_init(int *** info,int n_joints):

 *info = malloc(n_joints*sizeof(int*));
 if(*info == NULL) 
 printf("queues_init: malloc failed, errno: %d, meaning: %s\n", errno, strerror(errno));

 int i;
 for(i=0; i<n_joints; i++) {
 (*info)[i] = (int*) malloc(sizeof(int));
 *(*info)[i] = 0;
 }

 return;
 }

现在程序正常运行,感谢@ l3x的帮助。