在乒乓测试中使用 pthread 条件变量
Use pthread condition variable in ping-pong test
我在乒乓测试中使用 pthread 条件变量作为同步原语。乒乓测试由两个线程交替执行。每个线程写入另一个线程的内存并使用信号将其唤醒,然后在自己的内存上等待并休眠,稍后将由另一个线程写入。这是我的第一个版本。当我循环这个乒乓测试10,000次时它工作正常,但是当我改为100,000次时,它偶尔会挂起。 N=1,000,000 肯定会挂。我尝试调试并打印出每个循环的循环号,但在我添加打印语句后程序再也没有挂起,这很烦人。这是乒乓测试代码:
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]);
}
我很困惑。有人可以帮我解释为什么第一个版本挂起而第二个版本没有挂起吗?两个条件变量共享一个互斥锁是否正确?
谢谢。
谢谢大家,尤其是咖啡馆。这是我的最终代码,无需挂起即可运行。
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]);
}
}
首先,抱歉,我想把它放到评论中,但我还是不能。
好吧,在你的代码中,我不太了解什么是 "my_rank" 和 "dest",因为我认为 my_rank 应该在这些循环中有所不同,但我发现以下内容可能对您有所帮助:http://www.cs.cf.ac.uk/Dave/C/node31.html#SECTION003125000000000000000
据说:
You should always call pthread_cond_signal() under the protection of the same mutex used with the condition variable being signaled. Otherwise, the condition variable could be signaled between the test of the associated condition and blocking in pthread_cond_wait(), which can cause an infinite wait.
因为您在第一个版本中使用了多个互斥体,这可能就是原因。
管理员可以将其移到评论中吗?
问题出在这一行:
while (pthread_cond_wait(&cond[my_rank], &mutex[my_rank]) && messages[my_rank]!=dest);
如果 'dest' 线程在解锁 mutex[dest]
之后和锁定 mutex[my_rank]
之前得到调度,它将设置 messages[my_rank]
并向条件变量发出信号,之前这个线程调用pthread_cond_wait()
,所以这个线程会一直等待。
解决这个问题很简单:在等待条件变量之前测试messages[my_rank]
。你也不希望 &&
在这里,因为只要 messages[my_rank] != dest
为真,你总是想继续循环 - 你不想在第一个非零 return来自 pthread_cond_wait()
。所以如果你想忽略来自 pthread_cond_wait()
的错误(就像你原来的那样,如果你不使用错误检查或健壮的互斥锁,这是完全没问题的,因为这是唯一允许 pthread_cond_wait()
的时间失败),使用:
while (messages[my_rank] != dest)
pthread_cond_wait(&cond[my_rank], &mutex[my_rank]);
你的备用版本没有这个错误的原因是因为锁在向 dest
线程发送信号和等待条件变量之间持续保持,所以 dest
线程没有'没有机会 运行 直到我们肯定在等待。
关于你的补充问题:
Is it correct for two condition variable sharing a single mutex?
是的,这是允许的,但反过来是不允许的(你不能让两个线程同时等待同一个条件变量,使用不同的互斥体)。
我在乒乓测试中使用 pthread 条件变量作为同步原语。乒乓测试由两个线程交替执行。每个线程写入另一个线程的内存并使用信号将其唤醒,然后在自己的内存上等待并休眠,稍后将由另一个线程写入。这是我的第一个版本。当我循环这个乒乓测试10,000次时它工作正常,但是当我改为100,000次时,它偶尔会挂起。 N=1,000,000 肯定会挂。我尝试调试并打印出每个循环的循环号,但在我添加打印语句后程序再也没有挂起,这很烦人。这是乒乓测试代码:
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]);
}
我很困惑。有人可以帮我解释为什么第一个版本挂起而第二个版本没有挂起吗?两个条件变量共享一个互斥锁是否正确?
谢谢。
谢谢大家,尤其是咖啡馆。这是我的最终代码,无需挂起即可运行。
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]);
}
}
首先,抱歉,我想把它放到评论中,但我还是不能。
好吧,在你的代码中,我不太了解什么是 "my_rank" 和 "dest",因为我认为 my_rank 应该在这些循环中有所不同,但我发现以下内容可能对您有所帮助:http://www.cs.cf.ac.uk/Dave/C/node31.html#SECTION003125000000000000000
据说:
You should always call pthread_cond_signal() under the protection of the same mutex used with the condition variable being signaled. Otherwise, the condition variable could be signaled between the test of the associated condition and blocking in pthread_cond_wait(), which can cause an infinite wait.
因为您在第一个版本中使用了多个互斥体,这可能就是原因。
管理员可以将其移到评论中吗?
问题出在这一行:
while (pthread_cond_wait(&cond[my_rank], &mutex[my_rank]) && messages[my_rank]!=dest);
如果 'dest' 线程在解锁 mutex[dest]
之后和锁定 mutex[my_rank]
之前得到调度,它将设置 messages[my_rank]
并向条件变量发出信号,之前这个线程调用pthread_cond_wait()
,所以这个线程会一直等待。
解决这个问题很简单:在等待条件变量之前测试messages[my_rank]
。你也不希望 &&
在这里,因为只要 messages[my_rank] != dest
为真,你总是想继续循环 - 你不想在第一个非零 return来自 pthread_cond_wait()
。所以如果你想忽略来自 pthread_cond_wait()
的错误(就像你原来的那样,如果你不使用错误检查或健壮的互斥锁,这是完全没问题的,因为这是唯一允许 pthread_cond_wait()
的时间失败),使用:
while (messages[my_rank] != dest)
pthread_cond_wait(&cond[my_rank], &mutex[my_rank]);
你的备用版本没有这个错误的原因是因为锁在向 dest
线程发送信号和等待条件变量之间持续保持,所以 dest
线程没有'没有机会 运行 直到我们肯定在等待。
关于你的补充问题:
Is it correct for two condition variable sharing a single mutex?
是的,这是允许的,但反过来是不允许的(你不能让两个线程同时等待同一个条件变量,使用不同的互斥体)。