了解 posix 屏障机制

Understanding posix barrier mechanism

这是一段(非常简化,带有全局变量和其他 "smells")的 C 代码,它使用 posix 屏障原语来同步线程启动。

#include <pthread.h>
#include <stdio.h>

pthread_barrier_t barrier;

void* thread_func(void* aArgs)
{
  pthread_barrier_wait(&barrier);

  printf("Entering thread %p\n", (void*)pthread_self());
  int i;
  for(i = 0 ; i < 5; i++)
    printf("val is %d in thread %p \n", i, (void*)pthread_self());
}

int main()
{
  pthread_t thread_1, thread_2;
  pthread_barrier_init(&barrier, NULL, 2);

  pthread_create(&thread_1, NULL, (void*)thread_func, NULL);
  printf("Thread %p created\n", (void*)thread_1);

  usleep(500);

  pthread_create(&thread_2, NULL, (void*)thread_func, NULL);
  printf("Thread %p created\n", (void*)thread_2);

  pthread_join(thread_1, NULL);
  pthread_join(thread_2, NULL);

  pthread_barrier_destroy(&barrier);

  return 0;
}

我不明白,为什么 "Entering thread ..." 字符串在输出中不同时出现?当我 运行 以上程序时,通常会得到类似的输出:

Thread 0xb74fdb40 created
Thread 0xb6cfcb40 created
Entering thread 0xb6cfcb40
val is 0 in thread 0xb6cfcb40 
val is 1 in thread 0xb6cfcb40 
val is 2 in thread 0xb6cfcb40 
val is 3 in thread 0xb6cfcb40 
val is 4 in thread 0xb6cfcb40 
Entering thread 0xb74fdb40
val is 0 in thread 0xb74fdb40 
val is 1 in thread 0xb74fdb40 
val is 2 in thread 0xb74fdb40 
val is 3 in thread 0xb74fdb40 
val is 4 in thread 0xb74fdb40 

我期望的是同时启动两个线程,并在输出中按顺序出现 "Entering thread ..." 个字符串。 编译它:gcc barrier.c -pthread

我做错了什么?

屏障所做的就是确保在另一个线程进入屏障之前,任何线程都不能return来自屏障等待调用。除了每个单独的 stdio 调用是原子的之外,后续输出之间没有顺序关系。您在另一个线程的所有输出之前看到一个线程的所有输出这一事实仅仅是调度 and/or 的结果,哪个线程在每次尝试时首先成功获得 stdout 中的内部互斥锁(一旦它在一个上得到它并且另一个线程进入睡眠等待互斥锁,第一个线程有一个优势再次首先重新获取这个互斥锁。

如果您想看到交错的输出,请在每次调用 printf.

之前或之后立即在屏障上添加对 pthread_barrier_wait 的另一个调用

如果您将输出行数从 5 行增加到 10000 行左右,从统计角度来看,您更有可能偶然看到交错。

您的屏障所做的是阻止线程 1 在创建线程 2 之前产生任何输出。

两个线程都创建完成后,都跨过了barrier,都解除了阻塞。 在那之后,您不再对它们的交错方式进行任何控制。因此,线程 1 恰好获得了它的时间片并产生了它的所有输出;然后线程 2 获得它的时间片并产生它的所有输出。

尝试在 输出 "Enter" 之后移动屏障 以获得更好的理解。