В некоторых ядрах предусмотрена операция « flu sh» на семафоре для разблокирования всех задач, ожидающих на семафоре.
Например, VxWorks имеет semFlu sh () API, который атомарно разблокирует все задачи, отложенные для указанного семафора, т. Е. Все задачи будут разблокированы до того, как разрешено выполнение любых.
Я реализую класс C ++ в Linux, который ведет себя как двоичный семафор, а также имеет эту функциональность "flu sh". К сожалению, semaphore.h на Linux не предоставляет API типа flu sh () или broadcast ().
Что я пробовал: Использование условные переменные для реализации двоичного семафора . Вот мой псевдокод:
class BinarySem
{
BinarySem();
bool given;
mutex m;
condition_var cv;
give();
take();
take( Timeout T );
tryTake();
flush();
}
BinarySem::BinarySem()
: given(false)
{}
// take(Timeout T), tryTake() not shown
// to make question concise on StackOverflow
BinarySem::give()
{
{
lock_guard lk(m);
given = true;
}
cv.notify_one();
}
BinarySem::flush()
{
{
lock_guard lk(m);
given = true;
}
cv.notify_all();
}
BinarySem::take()
{
unique_lock lk(m);
while(!given)
{
cv.wait(lk);
}
given = false;
lk.unlock();
}
Однако этот flush()
не будет вести себя правильно. Скажем, у нас есть два потока, ожидающих BinarySem (то есть они оба вызвали take()
). Пусть эти потоки будут hiPrioThread
и loPrioThread
.
Когда для объекта BinarySem
вызывается flush()
, hiPrioThread
выходит из take()
и запускается. Когда он дает (hiPrioThread
просто дает, он еще не завершился), loPrioThread
все равно не сможет работать, потому что логическое значение given
теперь снова false
. Логическое значение требуется для защиты от ложных пробуждений.
Напротив, функция flush()
семафора должна просто разблокировать все потоки, и они могут запускаться всякий раз, когда у них появляется шанс.
Что если я не установлю given = false
в конце take()
? Это сделает мой код уязвимым для ложных пробуждений, и тогда несколько потоков могут разблокироваться при использовании give()
.
У кого-нибудь есть предложения?