使用导致奇怪行为的条件变量实现线程障碍

时间:2017-06-16 23:19:17

标签: c multithreading barrier

我试图使用条件变量为线程实现屏障系统,但是有一个警告,即一旦屏障填满,第一个到达的线程必须写入资源以与其余线程共享。问题是,当我运行程序时,广播调用不会唤醒大多数线程,我花了很长时间试图调试它没有成功。

如果我删除了对add_codeword()的调用,那么线程就会很好地组合在一起,我怀疑它与add_codeword()包含大约4秒的等待这一事实有关。

void join_meetup(char *value, int len) {

pthread_mutex_lock(&mut);
if(++count < grp_size) {
    if(count == 1) {
        add_codeword(value, len);  //<=== This has a wait() all of 4 seconds.
    }

    int curr_group = group;
    while(curr_group == group) {
        pthread_cond_wait(&queue, &mut);
    }

}else{
    if(meet_ord == MEET_LAST) {
        add_codeword(value, len);
    }

    count = 0; //Reset group counter.
    group++; //Increment the group num

    pthread_cond_broadcast(&queue);

}

read_resource(&code_list[(group-1) % CODE_SIZE], value, len);
pthread_mutex_unlock(&mut);

}

以下是组大小设置为3的示例输出:

Group 1: 1
Group 1: 1
Group 1: 1
INISHED WRITING CODE! 4
Group 2: 4
INISHED WRITING CODE! 7
Group 3: 7
Group 3: 7
Group 3: 7
Group 4: 10
FINISHED WRITING CODE! 13
Group 4: 10
Group 4: 10
Group 5: 13
FINISHED WRITING CODE! 16
Group 5: 13
Group 5: 13
Group 5: 13
Group 5: 13

如您所见,第2组只有1个线程,第5组有5个线程。

由于

1 个答案:

答案 0 :(得分:0)

您的代码中似乎有竞争条件。特别是,看起来你假设当一个线程从它的条件循环中醒来时,变量'group'将比它们进入时高一个,这并不总是正确的。想象一下,当你有非常“懒惰”的线程需要很长时间才能在发出信号后实际运行时会发生什么。当他们点击这一行时:

read_resource(&code_list[(group-1) % CODE_SIZE], value, len);
与该特定线程输入时相比,后续线程

'group'可能已经更新多次次。试试这个:

void join_meetup(char *value, int len) 
{
  pthread_mutex_lock(&mut);

  int my_group = group;

  if (++count < grp_size) 
  {
    if (count == 1)
        add_codeword(value, len);  //<=== This has a wait() all of 4 seconds.

    while (group == my_group)
        pthread_cond_wait(&queue, &mut);    
  }
  else
  {
    if (meet_ord == MEET_LAST)
        add_codeword(value, len);

    count = 0; //Reset group counter.
    group++;   //Increment the group num

    pthread_cond_broadcast(&queue);    
  }

  read_resource(&code_list[my_group % CODE_SIZE], value, len);
  pthread_mutex_unlock(&mut);
}

这应该确保线程获得适合其组的资源(忽略数组上的环绕+模数)。当然,没有真正的保证,他们会唤醒并继续他们正在做的其他事情。我也怀疑这段代码:

    if (meet_ord == MEET_LAST)
        add_codeword(value, len);

因为看起来新组的第一个线程负责为组执行add_codeword。那么,为什么另一个线程呢呢呢?