在乒乓测试中使用pthread条件变量

时间:2015-08-12 11:24:10

标签: c multithreading performance parallel-processing pthreads

我在乒乓测试中使用pthread条件变量作为同步原语。乒乓测试包括两个执行交替的线程。每个线程写入另一个线程的内存并使用信号将其唤醒,然后在其自己的内存上等待并休眠,稍后将由另一个线程写入。这是我的第一个版本。当我将这个乒乓测试循环10,000次时,它工作正常,但是当我改为100,000次时,它会偶尔挂起。 N = 1,000,000将使它明确挂起。我尝试调试并打印出每个循环的循环编号,但是在添加print语句之后程序永远不会再次挂起,这很烦人。这是乒乓球测试代码:

for(i=0; i<N+1; i++)
{
    if(i==N)
    {
        pthread_cond_signal(&cond[dest]);
        break;
    }
    pthread_mutex_lock(&mutex[dest]);
    messages[dest]=my_rank;
    pthread_cond_signal(&cond[dest]);
    pthread_mutex_unlock(&mutex[dest]);
    pthread_mutex_lock(&mutex[my_rank]);
    while(pthread_cond_wait(&cond[my_rank], &mutex[my_rank]) && messages[my_rank]!=dest);
    messages[my_rank]=my_rank;
    pthread_mutex_unlock(&mutex[my_rank]);
    printf("rank=%ld i=%ld messages[%ld]=%ld\n", my_rank, i, my_rank, messages[my_rank]);
}

然后我尝试了第二个版本,它可以工作,永不挂起,即使我将N设置为1,000,000。我从两个互斥锁更改为一个互斥锁,这两个互斥锁由两个条件变量共享。我不确定这是否是正确的方法但是这个从未再次挂起。这是代码:

for(i=0; i<N+1; i++)
{
    if(i==N)
    {
        pthread_cond_signal(&cond[dest]);
        break;
    }
    pthread_mutex_lock(&mutex[0]);
    messages[dest]=my_rank;
    pthread_cond_signal(&cond[dest]);
    while(pthread_cond_wait(&cond[my_rank], &mutex[0]) && messages[my_rank]!=dest);
    messages[my_rank]=my_rank;
    pthread_mutex_unlock(&mutex[0]);
}

我很困惑。有人可以帮我解释为什么第一个版本挂起但第二个版本没有?两个条件变量共享一个互斥锁是否正确?

感谢。

感谢大家,特别是caf。这是我的最终代码,无需挂起。

for(i=0; i<N+1; i++)
{
    pthread_mutex_lock(&mutex[dest]);
    messages[dest]=my_rank;
    pthread_cond_signal(&cond[dest]);
    pthread_mutex_unlock(&mutex[dest]);
    if(i!=N)
    {
        pthread_mutex_lock(&mutex[my_rank]);
        while(messages[my_rank]!=dest)
            pthread_cond_wait(&cond[my_rank], &mutex[my_rank]);
        messages[my_rank]=my_rank;
        pthread_mutex_unlock(&mutex[my_rank]);
    }
}

2 个答案:

答案 0 :(得分:1)

首先,抱歉,我想将其置于评论中,但我仍然不能。

嗯,在你的代码中,我不太了解什么是&#34; my_rank&#34;和#34; dest&#34;,因为我认为my_rank应该可以在这些循环内变化,但我发现以下内容可能会对您有所帮助:http://www.cs.cf.ac.uk/Dave/C/node31.html#SECTION003125000000000000000

它说:

  

您应始终在与发出信号的条件变量一起使用的相同互斥锁的保护下调用pthread_cond_signal()。否则,条件变量可以在相关条件的测试和pthread_cond_wait()中的阻塞之间发出信号,这可能导致无限等待。

当您在第一个版本中使用多个互斥锁时,可能就是原因。

管理员可以将其移到评论中吗?

答案 1 :(得分:1)

问题出在这一行:

while (pthread_cond_wait(&cond[my_rank], &mutex[my_rank]) && messages[my_rank]!=dest);

如果在解锁mutex[dest]之后锁定mutex[my_rank]之前安排'dest'主题,则会设置messages[my_rank]并在之前发出条件变量的信号>此线程调用pthread_cond_wait(),因此该线程将永远等待。

对此的修复非常简单:在等待条件变量之前测试messages[my_rank] 。你也不希望&&在这里,因为只要messages[my_rank] != dest为真,你总是想保持循环 - 你不想在{{1}的第一次非归零时突破}}。因此,如果您想忽略来自pthread_cond_wait()的错误(就像您的原始错误一样,如果您没有使用错误检查或强大的互斥锁,这是完全正常的,因为这是唯一允许pthread_cond_wait()次失败),使用:

pthread_cond_wait()

您的备用版本没有此错误的原因是因为在发出while (messages[my_rank] != dest) pthread_cond_wait(&cond[my_rank], &mutex[my_rank]); 线程信号并等待条件变量之间持续保持锁定,因此dest线程无法获取有机会跑,直到我们肯定在等待。

至于你的补充质询:

  

两个条件变量共享一个互斥锁是否正确?

是的,这是允许的,但反之则不然(你不能让两个线程同时使用不同的互斥锁等待相同的条件变量)。