首页 > 操作系统 > 多线程中壁垒(barrier)的使用

多线程中壁垒(barrier)的使用

2010年1月27日 行者 发表评论 阅读评论

  前面我们讲过main()函数与工作线程结束进行的同步,在那里提到了两种方式:pthread_join()函数以及壁垒(barrier)。

  现在我们回到房子的比喻,假设这个家庭准备到哪个地方旅行。司机上了小货车并发动了引擎。之后,司机就开始等待。只有全部的家庭成员都上车之后,这个小货车才会开动——因为我们不想把任何人落下!

  这和我们在前面说的那个绘图程序的原理是一模一样的。主线程要等待全部工作线程结束后,才执行下一步的程序。

  不过和这个比喻还有一个很大的差别。那就是通过使用pthread_join()函数,我们是等待所有工作线程的结束。也就是说,之后这些线程已经不存在了,它们退出了。

  通过使用壁垒(barrier),我们可以等待某些数量的线程在壁垒处集合。在设定的数目达到之后,我们解锁这些线程,让它们继续运行。

  你先要使用pthread_barrier+init()函数来创建壁垒:

#include <pthread.h>

int
pthread_barrier_init (pthread_barrier_t *barrier,
                      const pthread_barrierattr_t *attr,
                      unsigned int count);

  这段程序在传送的地址处(指向壁垒对象的指针barrier)创建一个壁垒对象,这个壁垒对象的属性通过attr进行设置,我们也可以使用NULL来使用默认设置。必须调用pthread_barrier_wait()函数的线程的个数通过count设定。

  一旦壁垒创建成功之后,我们就可以让线程在其结束之后调用pthread_barrier_wait()函数来声明其已经结束。代码如下:

#include <pthread.h>

int
pthread_barrier_wait (pthread_barrier_t *barrier);

  当一个线程调用pthread_barrier_wait()函数,它就会进入阻塞状态,直到在pthread_barrier_init()函数中设定的那么多数量的线程调用pthread_barrier_wait()函数为止。当正确数量的线程调用了那个函数,所有的这些线程就会被“同时”解除阻塞。

  例子如下:

/*
 *  barrier1.c
*/

#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <sys/neutrino.h>

pthread_barrier_t   barrier; // the barrier synchronization object

void *
thread1 (void *not_used)
{
    time_t  now;
    char    buf [27];

    time (&now);
    printf ("thread1 starting at %s", ctime_r (&now, buf));

    // do the computation
    // let's just do a sleep here...
    sleep (20);
    pthread_barrier_wait (&barrier);
    // after this point, all three threads have completed.
    time (&now);
    printf ("barrier in thread1() done at %s", ctime_r (&now, buf));
}

void *
thread2 (void *not_used)
{
    time_t  now;
    char    buf [27];

    time (&now);
    printf ("thread2 starting at %s", ctime_r (&now, buf));

    // do the computation
    // let's just do a sleep here...
    sleep (40);
    pthread_barrier_wait (&barrier);
    // after this point, all three threads have completed.
    time (&now);
    printf ("barrier in thread2() done at %s", ctime_r (&now, buf));
}

main () // ignore arguments
{
    time_t  now;
    char    buf [27];

    // create a barrier object with a count of 3
    pthread_barrier_init (&barrier, NULL, 3);

    // start up two threads, thread1 and thread2
    pthread_create (NULL, NULL, thread1, NULL);
    pthread_create (NULL, NULL, thread2, NULL);

    // at this point, thread1 and thread2 are running

    // now wait for completion
    time (&now);
    printf ("main () waiting for barrier at %s", ctime_r (&now, buf));
    pthread_barrier_wait (&barrier);

    // after this point, all three threads have completed.
    time (&now);
    printf ("barrier in main () done at %s", ctime_r (&now, buf));
}

  主线程创建了壁垒并对其初始化,设定需要通过壁垒同步的线程的个数(也包括了它自己)。在我们的例子里面,个数为3——一个是main()线程,一个是thread1(),一个是thread2()。之后图像计算线程(thread1()与thread2())开始运行。为了演示,我们没有列出图形计算的源代码,而是使用了sleep(20)和sleep(40)两个函数,来完成延迟,就像运算正在进行似的。为了同步,主线程在壁垒处阻塞了自己,在两个工作线程也在壁垒处集合之后,才会对其解除阻塞。

  如前面所讲的,工作线程通过pthread_join()函数,只有这些工作线程结束并消亡之后主线程才能与它们同步。不过通过壁垒,这些线程可以继续存活。在实际中,它们是在全部结束之后从pthread_barrier_wait()函数处解除阻塞。这里的主意是让你准备好让这些线程做些事。在我们的图像的例子里面,它们没什么事情可做,因为我们就是这样写的代码的。在实际的应用中,你可能会让它们开始下一帧的计算了。

Related posts:

  1. 用于线程同步的条件变量(Condition Variables)
  2. 线程的启动
  3. 线程池(Pools of threads)
  4. 进程的启动
  5. 用于线程同步的Sleepon锁

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.