线程同步的障碍

Posted

技术标签:

【中文标题】线程同步的障碍【英文标题】:Barriers for thread syncing 【发布时间】:2011-04-16 23:07:19 【问题描述】:

我正在创建 n 个线程,然后在障碍击穿后开始执行。

在全局数据空间中:

int bkdown = 0;

在 main() 中:

pthread_barrier_init(&bar,NULL,n);

for(i=0;i<n;i++)

pthread_create(&threadIdArray[i],NULL,runner,NULL);
if(i==n-2)printf("breakdown imminent!\n");
if(i==n-1)printf("breakdown already occurred!\n");

在线程运行器函数中:

void *runner(void *param)

 pthread_barrier_wait(&bar);

 if(bkdown==0)bkdown=1;printf("barrier broken down!\n");

        ...

 pthread_exit(NULL);

预期顺序:

breakdown imminent!
barrier broken down!
breakdown already occurred!

实际顺序: (反复测试)

breakdown imminent!
breakdown already occurred!
barrier broken down!!

有人可以解释为什么我在"already occurred" 消息之前没有收到"broken down" 消息吗?

【问题讨论】:

【参考方案1】:

线程的运行顺序取决于操作系统。仅仅因为您启动一个线程并不意味着操作系统会立即运行它。

如果你真的想控制线程的执行顺序,你必须在其中放置某种同步(使用互斥锁或条件变量。)

【讨论】:

【参考方案2】:
for(i=0;i<n;i++)

pthread_create(&threadIdArray[i],NULL,runner,NULL);
if(i==n-2)printf("breakdown imminent!\n");
if(i==n-1)printf("breakdown already occurred!\n");

i == n-1 之前没有什么能阻止这个循环的执行。 pthread_create() 只是触发要运行的线程。它不会等待它开始或结束。因此,您受调度程序的支配,它可能决定继续执行您的循环,或切换到新创建的线程之一(或在 SMP 系统上同时执行)。

您还初始化了n 的屏障,因此在任何情况下,在您创建所有线程之前,所有线程都不会越过屏障。

【讨论】:

【参考方案3】:

除了 nos 和 Starkey 的答案之外,您还必须考虑到您的代码中还有另一个经常被忽略的序列化:您正在同一个 FILE 变量上执行 IO,即 stdin

对该变量的访问在内部是互斥的,您的n+1 线程(包括您的调用线程)访问该互斥的顺序是实现定义的,在您的情况下基本上是随机的。

因此,您获得printf 输出的顺序就是您的线程通过这些虫洞的顺序。

【讨论】:

【参考方案4】:

您可以通过以下两种方式之一获得预期的订单

创建优先级高于主线程的每个线程。这将确保新线程在创建后立即运行并在屏障上等待。 将“故障迫在眉睫!\n”打印移到 pthread_create() 之前,并在每个 pthread_create() 之后调用使用 sched_yield() 调用。这将安排新创建的线程执行。

【讨论】:

以上是关于线程同步的障碍的主要内容,如果未能解决你的问题,请参考以下文章

java中的简单屏障同步

Java 并发:倒计时锁存器与循环障碍

Windows 中的进程间同步屏障

OpenCL 中的障碍

倒计数锁存器(CountDown Latch)和 CyclicBarrier(同步屏障)

线程的线程的同步