通常,一组协作线程将在循环中执行一系列步骤,完成每个步骤之后在屏障处同步。 对于这个应用程序,我们需要一个可重复使用的屏障,在所有线程通过后锁定自身。
为了解决这个问题,我们可以使用两个旋转栅门。
最初第一个被锁定,第二个被打开。当所有线程到达第一个时,我们锁定第二个并解锁第一个。当所有线程到达第二个时,我们重新锁定第一个,这使得线程可以安全地循环到开头,然后打开第二个。
此解决方案有时被称为两阶段屏障(two-phase barrier),因为它强制所有线程等待两次:一次是所有线程到达,另一次是所有线程执行临界区。
初始化
osSemaphoreId_t sem_mutex;
sem_mutex = osSemaphoreNew(1, 1, NULL);
osSemaphoreId_t sem_turnstile;
sem_turnstile = osSemaphoreNew(1, 0, NULL);
osSemaphoreId_t sem_turnstile2;
sem_turnstile2 = osSemaphoreNew(1, 1, NULL);
int count = 0;
void critical_point()
{
static int num = 0;
num++;
printf("num = %d \r\n", num);
}
3个线程共用一份代码
osSemaphoreAcquire(sem_mutex, osWaitForever);
count++;
if(count == 3)
{
printf("rendezvous 1...\r\n");
osSemaphoreAcquire(sem_turnstile2, osWaitForever);/* lock 2 */
osSemaphoreRelease(sem_turnstile); /* unlock 1 */
}
osSemaphoreRelease(sem_mutex);
osSemaphoreAcquire(sem_turnstile, osWaitForever); /* 1 turnstile */
osSemaphoreRelease(sem_turnstile);
critical_point();
osSemaphoreAcquire(sem_mutex, osWaitForever);
count--;
if(count == 0)
{
printf("rendezvous 2...\r\n");
osSemaphoreAcquire(sem_turnstile, osWaitForever);/* lock 1 */
osSemaphoreRelease(sem_turnstile2); /* unlock 2 */
}
osSemaphoreRelease(sem_mutex);
osSemaphoreAcquire(sem_turnstile2, osWaitForever); /* 2 turnstile */
osSemaphoreRelease(sem_turnstile2);
结论:
可以明显看到在执行临界代码段,是在两个会合之间;