Скажем, у меня есть 3 функции, которые могут быть вызваны верхним слоем:Есть ли способ синхронизировать это без блокировок?
Start
- будет вызываться только если мы не были начаты еще, или остановка была ранее называласьStop
- будет только после успешного звонка в началоProcess
- можно позвонить по номеру любой номер (одновременно на разные темы); если запущенно, будет вызывать в нижний слой
В Stop
, он должен ждать, пока все Process
звонков закончить вызов в нижний слой, и предотвратить любые дальнейшие вызовы. С запорным механизмом, я могу придумать следующий псевдокод:
Start() {
ResetEvent(&StopCompleteEvent);
IsStarted = true;
RefCount = 0;
}
Stop() {
AcquireLock();
IsStarted = false;
WaitForCompletionEvent = (RefCount != 0);
ReleaseLock();
if (WaitForCompletionEvent)
WaitForEvent(&StopCompleteEvent);
ASSERT(RefCount == 0);
}
Process() {
AcquireLock();
AddedRef = IsStarted;
if (AddedRef)
RefCount++;
ReleaseLock();
if (!AddedRef) return;
ProcessLowerLayer();
AcquireLock();
FireCompletionEvent = (--RefCount == 0);
ReleaseLock();
if (FilreCompletionEvent)
SetEvent(&StopCompleteEvent);
}
Есть ли способ добиться того же поведения без запирающего механизма? Возможно, с некоторым причудливым использованием InterlockedCompareExchange и InterlockedIncremenet/InterlockedDecrement?
Причина, по которой я спрашиваю, заключается в том, что это путь передачи данных сетевого драйвера, и я бы предпочел не иметь никаких замков.
Если присвоение 'IsStarted' является атомарным, вам даже нужны блокировки? «WaitForCompletionEvent» может быть другим. –
Используйте C стандартную 'stdatomics'. – Olaf
Поскольку несколько вызовов процесса (в ProcessLowerLayer) могут перекрывать вызов «Стоп», важно, чтобы я дождался завершения всех операций до того, как Stop вернется. –