多线程中壁垒(barrier)的使用
前面我们讲过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:
近期评论