最近在学MIT6.828,做了HomeWork9:barriers。
大意就是实现一个线程屏障,多个线程都会调用barrier()
函数,然后要求所有的线程都进入此barrier函数后才能依次离开barrier。
我的实现是这样的:
/*nthread为总的线程个数,bstate.nthread是初值为0的一个计数器*/
static void barrier()
{
#define wait() pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex)
#define notify() pthread_cond_broadcast(&bstate.barrier_cond)
static int resume = 0; // 表示wait1,wait2的状态
pthread_mutex_lock(&bstate.barrier_mutex);
++bstate.nthread; // safe
notify();
while (bstate.nthread < nthread && !resume)
wait(); // wait1
resume = 1; // 避免有线程执行--bstate.nthread破坏了已触发的wait1的条件,
--bstate.nthread;
if (bstate.nthread == 0)
bstate.round++;
notify();
while (bstate.nthread > 0 && resume)
wait(); // wait2
resume = 0; // 避免有线程执行++bstate.nthread破坏了已触发的wait2的条件,
pthread_mutex_unlock(&bstate.barrier_mutex);
#undef wait
#undef notify
}
但是当我尝试在网上搜索标准答案时,清一色的实现是这样的:
static void barrier()
{
pthread_mutex_lock(&bstate.barrier_mutex);
bstate.nthread++;
if (bstate.nthread == nthread)
{
// 最后一个进程进入 执行 round++, 再唤醒其他进程。
bstate.round++;
bstate.nthread = 0;
// 唤醒其他进程
pthread_cond_broadcast(&bstate.barrier_cond); // BBB
}
else
{ // 不存在假唤醒问题吗?
pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex); // AAA
}
pthread_mutex_unlock(&bstate.barrier_mutex);
}
经过不充分测试,两种实现都能正常运行。
但是,我觉得网上的实现存在假唤醒风险(小白拙见,如有误解请指出):
- 正常情况下,如果一共是4个线程,那么当前三个线程进入后,他们都会被堵塞在AAA语句中,直到第四个线程进入后执行了BBB语句,前3个线程都会从wait中醒来,然后依次获取锁解锁再退出
barrier()
。 - 但是,如果前三个线程堵塞在AAA后,线程4还没有进入
barrier()
函数,然后此时发生了操作系统层面的假唤醒,导致前3个线程从wait中返回,这时它们就会直接退出barrier()
,这就违反了屏障的定义。
希望有高人指点。