Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
if (readerCount > 0)
{
waitingWriter = TRUE;
LeaveCriticalSection(&countsLock);
WaitForSingleObject(noReaders, INFINITE);
}
и тут же другой писатель может перехватить контроль. В итоге первый писатель может остаться ждать в тот момент, когда читателей и писателей реально нет
Так при отпуске секции надо «будить» всех ждущих.
Почему, если у нас выставлен флаг waitingWriter? Второй писатель не должен получить доступ, раз уже есть один ожидающий — он должен сам свалиться в Wait, а тем временем будет разбужен первый писатель.
то опять же, все возвращается к тому случаю, когда управление может перехватить читатель.
Если после отпускания секции и перед началом ожидания события сперва встрянет читатель, то он скинет этот флаг при разблокировке
Тем не менее, эта задача решается с одной блокировкой.
Это не должно влиять на ожидание писателем, он будет по-прежнему в очереди. При выполнении операции «отпуск» мы видим, что у нас есть ожидающий писатель, и можем разбудить его. Или же читателя в противном случае.
Нужен счетчик, а не флаг в таком случае.
Может быть, тогда вы представите это решение?
Вы совсем не слышите, что вам говорят. В момент перехвата читателем и в момент его отпуска нет никаких ожидающих писателей. Либо есть ожидающий писатель, но не исходный, а другой — тоже перехвативший управление.
Либо вы что-то не понимаете в многопоточности, либо мои понятия о ней устарели. Счетчик вас не спасет, потому что читатель может перехватить управление несколько раз подряд, успешно обнулив счетчик.
Честно говоря, дискуссия теряет смысл, потому что вы продолжаете твердить свое, придумывая одну идею за другой. Предлагаю вам представить ваше решение проблемы, тогда будет предмет для конструктивного обсуждения.
MustWait := False;
EnterCriticalSection(Lock);
try
ThreadId := GetCurrentThreadId;
Index := FindThread(ThreadId);
if Index < 0 then
begin
// Request to write (first time)
AddToThreadList(ThreadId, False);
if State = 0 then
begin
// unowned so start writing
State := -1;
end
else
begin
// owned, must wait
Inc(WaitingWriters);
MustWait := True;
end;
end
else
begin
...
...
end;
finally
LeaveCriticalSection(Lock);
end;
if MustWait then
WaitForSingleObjectEx(SemWriters, INFINITE, True);
....
....
procedure Release
if State = 0 then
ReleaseWaiters(WasReading);
procedure ReleaseWaiters
... если решили дать зеленый свет писателям:
State := -1;
Dec(WaitingWriters);
ReleaseSemaphore(SemWriters, 1, nil);
An SRW lock is the size of a pointer. The advantage is that it is fast to update the lock state. The disadvantage is that very little state information can be stored, so SRW locks cannot be acquired recursively.
Строго говоря, да, под XP у нас reentrant, а под все остальное нет.
Results are undefined if the calling thread holds the read-write lock (whether a read or write lock) at the time the call is made.
Windows 7/8/10
Чем изобретать велосипед, для WinXP лучше пользоваться недокументированными функциями: RtlAcquireResourceShared() (лок на чтение) и RtlAcquireResourceExclusive (лок на запись).
Пример на Delphi, как это можно обернуть в RWLock интерфейс: u_ReadWriteSyncRtlResource.pas.
Тот же StackOverflow рекомендует: Is there a cross platform version of window vista's slim reader writer locks?
Чем плохи std::shared_mutex и boost::shared_mutex ???
Портабельный RWLock для Windows