第3讲中的会合,只适合于两个线程之间,如果多个线程就不合适;
进一步推广会合解决方案。 每个线程都应该运行以下代码:
屏障的概念:屏障是多线程各自做自己的工作,如果某一线程完成了工作,就等待在屏障那里,直到其他线程的工作都完成了,再一起做别的事;举个通俗的例子:在百米赛跑里,比赛没开始之前,每个运动员都在赛场上自由活动,有的热身,有的喝水,有的跟教练谈论。比赛快开始时,准备完毕的运动员就预备在起跑线上,如果有个运动员还没准备完(除去特殊情况),他们就一直等,直到运动员都在起跑线上,裁判喊口号后再开始跑。这里的起跑线就是屏障,做完准备工作的运动员都等在起跑线,直到其他运动员也把准备工作做完!
1、屏障1解决方案
互斥锁信号量初始化
osSemaphoreId_t sem_mutex;
sem_mutex = osSemaphoreNew(1, 1, NULL);
屏障信号量初始化
osSemaphoreId_t sem_turnstile;
sem_turnstile = osSemaphoreNew(1, 0, NULL);
线程数初始化
int count = 0;
临界区代码
void critical_point()
{
static int num = 0;
num++;
printf("num = %d \r\n", num);
}
线程1代码
osSemaphoreAcquire(sem_mutex, osWaitForever);
count++;
osSemaphoreRelease(sem_mutex);
if(count == 3)
{
printf("rendezvous...\r\n");
osSemaphoreRelease(sem_turnstile);
}
else
printf("thread 1 wait...\r\n");
osSemaphoreAcquire(sem_turnstile, osWaitForever);
osSemaphoreRelease(sem_turnstile);
critical_point();
线程2代码
osSemaphoreAcquire(sem_mutex, osWaitForever);
count++;
osSemaphoreRelease(sem_mutex);
if(count == 3)
{
printf("rendezvous...\r\n");
osSemaphoreRelease(sem_turnstile);
}
else
printf("thread 2 wait...\r\n");
osSemaphoreAcquire(sem_turnstile, osWaitForever);
osSemaphoreRelease(sem_turnstile);
critical_point();
线程3代码
osSemaphoreAcquire(sem_mutex, osWaitForever);
count++;
osSemaphoreRelease(sem_mutex);
if(count == 3)
{
printf("rendezvous...\r\n");
osSemaphoreRelease(sem_turnstile);
}
else
printf("thread 3 wait...\r\n");
osSemaphoreAcquire(sem_turnstile, osWaitForever);
osSemaphoreRelease(sem_turnstile);
critical_point();
输出
可以看到在3个线程会合后,再执行临界区代码;
这种模式经常发生,即一对快速连续的wait()和signal()函数,它有一个名字,被称为旋转栅门(十字转门)(turnstile),因为它允许一次通过一个线程,并且可以锁定以阻止所有线程。
在其初始状态(零),旋转栅门被锁定。 第n个线程解锁它,然后所有n个线程都通过。
缺点:
读取互斥锁之外的count值似乎很危险。 在这种情况下,这不是问题,但一般来说,这可能不是一个好主意。
与此同时,您可能需要考虑以下问题:在第n个线程之后,旋转门处于什么状态?barrier屏障可能发出多于一次的信号吗?