参考 https://blog.youkuaiyun.com/booksyhay/article/details/82696779
信号量也可用于表示队列。在这种情况下,初始值为0,并且通常编写代码以确保不会发出信号,除非有线程在等待。因此信号量的值永远不会为正数。
例如,假设线程代表舞厅舞者,并且有两种舞者:领舞(leaders)和伴舞(followers),在进入舞池之前排队等候。 当领舞到达时,它会检查是否有伴舞在等待。如果是,他们就都可以进去。 否则就要等待。
类似地,当伴舞到达时,它会检查是否有领舞,相应地,选择继续或等待。
初始化
leaders和followers是计数器,记录每种等待的舞者的数量。 mutex保证对计数器的独占访问。
leaderQueue和followerQueue是舞者等待的队列。 rendezvous用于检查两个线程是否已完成跳舞。
解决方案
leaders
当领导者leader到达时,它会获得保护leaders和followers变量的互斥体mutex。 如果有追随者follower在等待,领导者会减少followers计数,给追随者发送信号,然后在释放互斥锁mutex之前调用dance()。 这保证了只有一个追随者线程同时运行dance()。
如果没有追随者在等待,领导者必须在等待leaderQueue之前释放互斥锁。
原文链接:https://blog.youkuaiyun.com/booksyhay/article/details/82696779
followers
当追随者到达时,它会检查等待的领导者。 如果有一个,那么追随者会减少领导者计数leaders,向领导者发出信号并执行dance,而不释放互斥体mutex。 实际上,在这种情况下,追随者永远不会释放互斥锁; 而领导者会。 我们不必跟踪哪个线程具有互斥锁,因为我们知道其中有一个有,并且其中任何一个都可以释放它。 在我的解决方案中,它始终是领导者。
当一个信号量被用作队列时【用作队列的信号量与条件变量非常相似。 主要区别在于线程必须在等待之前显式释放互斥锁,并在之后显式重新获取它(但仅在它们需要时才重新获取)。】,我发现这样很有用:将“等待”看作“等待这个队列”,“发送信号”看作“让这个队列中有人离开”。
在这段代码中,除非有人在等待,否则我们永远不会发出队列信号,因此队列信号量的值很少是正数。 但是有可能。 看看你是否能弄明白。
原文链接:https://blog.youkuaiyun.com/booksyhay/article/details/82696779
osSemaphoreId_t sem_mutex;
sem_mutex = osSemaphoreNew(1, 1, NULL);
osSemaphoreId_t sem_leaders;
sem_leaders = osSemaphoreNew(1, 0, NULL);
osSemaphoreId_t sem_followers;
sem_followers = osSemaphoreNew(1, 0, NULL);
osSemaphoreId_t sem_rendezvous;
sem_rendezvous = osSemaphoreNew(1, 0, NULL);
int count = 0;
int leaders = 0;
int followers = 0;
void dance()
{
static int num = 0;
num++;
printf("num = %d \r\n", num);
}
leaders线程
void func_leaders(void)
{
osSemaphoreAcquire(sem_mutex, osWaitForever);
if(followers > 0)
{
followers--;
osSemaphoreRelease(sem_followers);
}
else
{
leaders++;
osSemaphoreRelease(sem_mutex);
osSemaphoreAcquire(sem_leaders, osWaitForever);
}
dance();
osSemaphoreAcquire(sem_rendezvous, osWaitForever);
osSemaphoreRelease(sem_mutex);
printf("rendezvous\r\n");
}
followers线程
void func_followers(void)
{
osSemaphoreAcquire(sem_mutex, osWaitForever);
if(leaders > 0)
{
leaders--;
osSemaphoreRelease(sem_leaders);
}
else
{
followers++;
osSemaphoreRelease(sem_mutex);
osSemaphoreAcquire(sem_followers, osWaitForever);
}
dance();
osSemaphoreRelease(sem_rendezvous);
}
创建2个leaders线程,3个followers线程
结论:
可以看到,即使有2个leaders和3个followers,但是每次都只有一个leader和一个follower一起进入舞池跳舞;