Как уже упоминалось в другом ответе, вам нужен Fair Mutex, и Ticket Lock может быть одним из способов его реализации.
Есть другой способ, основанный на двоичном семафоре, и он на самом деле близко к тому, что раньше было критическим разделом. Например:
class old_cs
{
public:
old_cs()
{
event = CreateEvent(NULL, /* bManualReset = */ FALSE, /* bInitialState =*/ TRUE, NULL);
if (event == NULL) throw std::runtime_error("out of resources");
}
~old_cs()
{
CloseHandle(event);
}
void lock()
{
if (count.fetch_add(1, std::memory_order_acquire) > 0)
WaitForSingleObject(event, INFINITE);
}
void unlock()
{
if (count.fetch_sub(1, std::memory_order_release) > 1)
SetEvent(event);
}
old_cs(const old_cs&) = delete;
old_cs(old_cs&&) = delete;
old_cs& operator=(const old_cs&) = delete;
old_cs& operator=(old_cs&&) = delete;
private:
HANDLE event;
std::atomic<std::size_t> count = 0;
};
В документации Объекты критических разделов можно найти следующее *1009*:
Начиная с Windows Server 2003 с пакетом обновления 1 ( SP1), потоки, ожидающие в критической секции, не получают критическую секцию в порядке поступления. Это изменение значительно повышает производительность для большей части кода. Однако некоторые приложения зависят от порядка «первым пришел - первым вышел» (FIFO) и могут работать плохо или не работать вообще в текущих версиях Windows (например, приложения, которые использовали критические секции в качестве ограничителя скорости). Чтобы ваш код продолжал работать правильно, вам может потребоваться добавить дополнительный уровень синхронизации. Например, предположим, что у вас есть поток производителя и поток потребителя, которые используют объект критического раздела для синхронизации своей работы. Создайте два объекта события, по одному для каждого потока, чтобы указать, что он готов для продолжения другого потока. Поток потребителя будет ждать, пока производитель сообщит о своем событии, прежде чем войти в критическую секцию, а поток производителя будет ждать, пока поток потребителя не сообщит о своем событии, прежде чем войти в критическую секцию. После того, как каждый поток покидает критический раздел, он сообщает о своем событии, чтобы освободить другой поток.
Таким образом, алгоритм в этом посте является упрощенной версией того, что раньше было в критическом разделе в Windows XP и более ранних версиях. .
Приведенный выше алгоритм не является полным критическим разделом, в нем отсутствуют поддержка рекурсии, вращение, обработка ситуаций с низким уровнем ресурсов.
Также он опирается на Windows Справедливость событий.