[英]Multiple threads waiting for same semaphore
Suppose there are 5 threads waiting for a semaphore 假设有5个线程在等待信号量
CreateSemaphore(sem_bridgempty,0,1,INFINITE);
WaitForSingleObject(sem_bridgempty, INFINITE);
Now when sem_bridgeempty is signalled, one of the 5 threads will wake up and rest will again wait for sem_bridgeempty
to be signalled.Am i right here? 现在,当发出sem_bridgeempty信号时,这5个线程之一将唤醒,其余线程将再次等待sem_bridgeempty
发出信号。我在这里吗?
I am implementing one lane bridge problem where there can be vehicles moving from one direction only at a time.Also the capacity of the bridge is fixed at 5.What i have done so far is 我正在实施一个车道桥问题,即一次只能有一个方向行驶的车辆。而且桥的容量固定为5.我到目前为止所做的是
unsigned WINAPI enter(void *param)
{
int direction = *((int *)param);
while (1)
{
WaitForSingleObject(sem_bridgecount, INFINITE);
WaitForSingleObject(mut_mutex, INFINITE);
if (curr_direction == -1 || direction == curr_direction)
{
curr_direction = direction;
cars_count++;
std::cout << "Car with direction " << direction << " entered " << GetCurrentThreadId() << std::endl;
ReleaseMutex(mut_mutex);
break;
}
else
{
ReleaseMutex(mut_mutex);
WaitForSingleObject(sem_bridgempty, INFINITE);
}
}
Sleep(5000);
exit1(NULL);
return 0;
}
unsigned WINAPI exit1(void *param)
{
WaitForSingleObject(mut_mutex, INFINITE);
cars_count--;
std::cout << "A Car exited " << GetCurrentThreadId() << std::endl;
ReleaseSemaphore(sem_bridgecount, 1, NULL);
if (cars_count == 0)
{
curr_direction = -1;
std::cout << "Bridge is empty " << GetCurrentThreadId() << std::endl;
ReleaseSemaphore(sem_bridgempty, 1, NULL);
}
ReleaseMutex(mut_mutex);
return 0;
}
int main()
{
sem_bridgecount = CreateSemaphore(NULL, 5, 5, NULL);
sem_bridgempty = CreateSemaphore(NULL, 0, 1, NULL);
mut_mutex = CreateMutex(NULL, false, NULL);
//create threads here
}
Consider the below portion 考虑以下部分
else
{
ReleaseMutex(mut_mutex);
WaitForSingleObject(sem_bridgempty, INFINITE);
A car is going in direction 1.Now there are three enter requests with direction 2.All 3 will be blocked at WaitForSingleObject(sem_bridgempty, INFINITE);
一辆汽车向1号方向行驶。现在有3个方向2的输入请求。所有3个将在WaitForSingleObject(sem_bridgempty, INFINITE);
处阻塞WaitForSingleObject(sem_bridgempty, INFINITE);
.Now when the bridge goes empty.One of the three will be picked up.The one picked up will again make bridge non empty.Then the other two will still wait for the bridge to go empty even though the direction is same. 现在,当桥空了时,三个桥架中的一个将被拾起。一个被拾起的桥将再次使桥不为空。然后,即使方向相同,另外两个桥仍然将等待桥架变空。 So even though there is direction=2
car on the bridge, other cars with the same direction are still waiting for the sem_bridgempty
. 因此,即使桥上有direction=2
汽车,其他具有相同方向的汽车仍在等待sem_bridgempty
。 I even thought of using sem_bridgempty
as an event instead of semaphore
(setevent() in exit1()
when cars_count=0
and resetevent()
in enter()
when first car enters).But still all threads don't wake up. 我甚至想用的sem_bridgempty
作为一个事件,而不是semaphore
(在SetEvent的() exit1()
时cars_count=0
和resetevent()
中enter()
当第一辆车进入),但仍然是所有线程不会醒来。
The cleanest option would be to use a critical section and a condition variable. 最干净的选择是使用关键部分和条件变量。
The ENTER algorithm would look like this: ENTER算法如下所示:
The EXIT algorithm would look like this: EXIT算法如下所示:
The condition variable could be an integer whose magnitude represents the number of cars on the bridge and whose sign represents the direction of travel. 条件变量可以是整数,其大小表示桥梁上的轿厢数量,其符号表示行进方向。
If you wanted to avoid condition variables, the simplest solution I could come up with requires one critical section and three auto-reset events: one for each direction of travel, plus one to indicate that the bridge is empty. 如果要避免使用条件变量,那么我能想到的最简单的解决方案需要一个关键部分和三个自动重置事件:一个用于每个行驶方向,另一个用于指示桥是空的。 You will also need a variable representing the number of cars on the bridge. 您还将需要一个变量,代表桥上的汽车数量。
The ENTER algorithm would look like this: ENTER算法如下所示:
The EXIT algorithm would look like this: EXIT算法如下所示:
need create objects which most corresponded to task. 需要创建最符合任务的对象。 in current task - we have 2 queues - on both direction. 在当前任务中-我们有2个队列-双向。 both this queue is FIFO by sense. 这两个队列在意义上都是FIFO。 and we need have ability wake exactly count of entries in queue - not only one or all. 并且我们需要具有唤醒队列中条目总数的能力-不仅仅是一个或全部。 the windows semaphore is exactly correspond to this. Windows信号量与此完全对应。 this is FIFO queue and by call ReleaseSemaphore
we can exactly set amount of threads (entries) to wake - this is second parameter of api lReleaseCount . 这是FIFO队列,通过调用ReleaseSemaphore
我们可以精确设置要唤醒的线程(条目)数量-这是api lReleaseCount的第二个参数。 in case event or ConditionVariable we can only wake single or all waiters. 万一事件或ConditionVariable,我们只能唤醒一个或所有服务员。
your mistake not in that you select semaphore - this is the best choice for this task. 您的错误不是因为您选择了信号量-这是完成此任务的最佳选择。 you mistake that you select it for wrong essences - sem_bridgecount, sem_bridgempty - which is not queue by sence at all. 您会误认为您选择了错误的本质-sem_bridgecount,sem_bridgempty-这根本不是按感觉排队的。 you ned have 2 semaphores for 2 directions - HANDLE _hSemaphore[2];
您已向2个方向发送了2个信号灯HANDLE _hSemaphore[2];
- one semaphore per direction - create it as _hSemaphore[0] = CreateSemaphore(0, 0, MAXLONG, 0)
- initial count is 0 (!) and maximum count is unlimited (but can select any value >= 5). -每个方向一个信号量-创建为_hSemaphore[0] = CreateSemaphore(0, 0, MAXLONG, 0)
-初始计数为0(!),最大计数为无限(但可以选择_hSemaphore[0] = CreateSemaphore(0, 0, MAXLONG, 0)
5的任何值)。 when car try enter to bridge in direction and can not, because now another direction is active or no free space on bridge - it must wait on semaphore (in FIFO queue) _hSemaphore[direction]
. 当汽车尝试进入方向而不能进入桥时,因为现在另一个方向处于活动状态或桥上没有可用空间-它必须等待信号量(在FIFO队列中) _hSemaphore[direction]
。 and when car exit from bridge - he need check current situation on bridge and wake one or another direction on some exactly cars count ( n ) (not all or single) - so call ReleaseSemaphore(_hSemaphore[direction], n, 0);
当汽车从桥上驶出时-他需要检查桥上的当前状况并唤醒一些确切的汽车计数( n )上的一个或另一个方向 (不是全部或单个)-因此调用ReleaseSemaphore(_hSemaphore[direction], n, 0);
in general: 一般来说:
void enter(int direction)
{
EnterCriticalSection(..);
BOOL IsNeedWait = fn(direction);
LeaveCriticalSection(..);
if (IsNeedWait) WaitForSingleObject(_hSemaphore[direction], INFINITE)
}
and 和
void exit(int direction)
{
EnterCriticalSection(..);
direction = calc_new(direction);
if (int WakeCount = calc_wake_count(direction))
{
ReleaseSemaphore(_hSemaphore[direction], WakeCount, 0);
}
LeaveCriticalSection(..);
}
note that in every enter - car only once enter to CriticalSection and after wait on _hSemaphore[direction]
it just enter to bridge without again enter to cs and check conditions. 请注意,在每个回车中,汽车只有一次进入CriticalSection,在等待_hSemaphore[direction]
它只是进入桥接而没有再次进入cs并检查条件。 this is because we can calculate exactly cars count (not single or all) and direction in exit
- and wake only cars which and must enter to bridge, this will be impossible if use events or conditional variables 这是因为我们可以准确计算exit
轿厢数量(不是单个或全部)和方向-并仅唤醒必须进入桥梁的轿厢,如果使用事件或条件变量,这将是不可能的
despite solution with conditional variables and CS is possible, i think it not best because: thread after wait in SleepConditionVariableCS
- again enter to cs which is absolute not need we need or wake only single car by WakeConditionVariable
when really can multiple cars enter to bridge, or wake all by WakeAllConditionVariable
but in this case several threads in concurrent again try enter to the same cs and only one will be winner, another will be wait here count of waiting threads can be more than maximum place on bridge (5 in your case) - and some threads will be need begin wait again in loop. 尽管有条件变量和CS的解决方案是可能的,但我认为这不是最好的,因为: SleepConditionVariableCS
等待后线程-再次输入cs,这绝对是我们不需要的,或者当多个车真的可以进入桥接时,由WakeConditionVariable
唤醒单个车,或通过WakeAllConditionVariable
唤醒所有WakeAllConditionVariable
但在这种情况下,并发中的多个线程再次尝试输入相同的cs,只有一个将获胜,另一个将在这里等待,等待线程的数量可能超过网桥的最大位置(在您的情况下为5) -并且一些线程将需要开始再次在循环中等待。 all this can be avoid if correct use semaphore 如果正确使用信号量,可以避免所有这些情况
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.