理解posix屏障机制

时间:2015-02-22 21:42:04

标签: c multithreading pthreads posix

这是C代码的片段(非常简化,带有全局变量和其他“气味”),它使用posix barrier原语来sincronize线程开始。

#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;
}

我无法理解,为什么“输入线程...”字符串不会同时出现在输出中?当我在程序上运行时,通常会得到相似的输出:

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 

我所期望的是,同时启动两个线程,并在输出中依次出现“输入线程...”字符串。 编译它:gcc barrier.c -pthread

我做错了什么?

2 个答案:

答案 0 :(得分:2)

所有屏障都确保在其他线程进入之前,两个线程都不能从屏障等待调用返回。除了每个单独的stdio调用是原子的之外,后续输出之间没有排序关系。您在另一个线程的所有输出之前看到一个线程的所有输出的事实仅仅是调度和/或哪个线程在每次尝试时首先在stdout中获取内部互斥锁的结果(一旦它是得到它一个,另一个线程进入休眠状态等待互斥锁,第一个线程有一个优势,再次首先重新获取此互斥锁。)

如果您希望看到输出交错,请在每次拨打pthread_barrier_wait之前或之后立即在屏障上添加另一个printf来电。

如果你将输出行数从5增加到10000左右,你在统计上也会更有可能看到交错。

答案 1 :(得分:2)

你的障碍是阻止线程1在创建线程2之前产生任何输出。

创建两个线程后,两个线程都穿过屏障并被解除阻塞。 之后,你没有断言它们是如何交错的。因此,线程1碰巧得到它的时间片并产生它的所有输出;然后线程2得到它的时间片并产生它的所有输出。

尝试在“输入”输出之后移动障碍以更好地理解。