После прохождения этот вопрос с тем же названием и его ответы, я подумал попробовать что-то, что действительно должно работать только с использованием критической секции и, следовательно, должно быть намного быстрее, чем существующие решения (которые используют другие объекты ядра, такие как мьютекс или семафор)
Вот мои функции блокировки / разблокировки чтения / записи:
#include <windows.h>
typedef struct _RW_LOCK
{
CRITICAL_SECTION readerCountLock;
CRITICAL_SECTION writerLock;
int readerCount;
} RW_LOCK, *PRW_LOCK;
void InitLock(PRW_LOCK rwlock)
{
InitializeCriticalSection(&rwlock->readerCountLock);
InitializeCriticalSection(&rwlock->writerLock);
}
void ReadLock(PRW_LOCK rwlock)
{
EnterCriticalSection(&rwlock->readerCountLock); // In deadlock 1 thread waits here (see description below)
if (++rwlock->readerCount == 1)
{
EnterCriticalSection(&rwlock->writerLock); // In deadlock 1 thread waits here
}
LeaveCriticalSection(&rwlock->readerCountLock);
}
void ReadUnlock(PRW_LOCK rwlock)
{
EnterCriticalSection(&rwlock->readerCountLock);
if (--rwlock->readerCount == 0)
{
LeaveCriticalSection(&rwlock->writerLock);
}
LeaveCriticalSection(&rwlock->readerCountLock);
}
int WriteLock(PRW_LOCK rwlock)
{
EnterCriticalSection(&rwlock->writerLock); // In deadlock 3 threads wait here
}
void WriteUnlock(PRW_LOCK rwlock)
{
LeaveCriticalSection(&rwlock->writerLock);
}
А вот и функция потока. После звонка InitLock (&g_rwLock);
от main
я создал ПЯТЬ потоков попробовать эти замки.
void thread_function()
{
static int value = 0;
RW_LOCK g_rwLock;
while(1)
{
ReadLock(&g_rwlLock);
BOOL bIsValueOdd = value % 2;
ReadUnlock(&g_rwlLock);
WriteLock(&g_rwlLock);
value ++;
WriteUnlock(&g_rwlLock);
}
}
В идеале этот код должен работать без проблем. Но, к моему разочарованию, это не работает всегда. Иногда он попадает в тупик. Я скомпилировал это и запустил на Windows XP. Для создания потоков с использованием пула потоков я использую стороннюю библиотеку. Следовательно, здесь нельзя дать весь этот код, который включает в себя множество процедур инициализации и другие вещи.
Но вкратце, я хотел бы знать, может ли кто-нибудь, взглянув на приведенный выше код, указать, что не так с этим подходом?
Я прокомментировал в коде выше, где каждый поток (из ПЯТЬ потоков) продолжает ждать, когда случится тупик. (Я узнал об этом, подключив отладчик к заблокированному процессу)
Любые входные данные / предложения были бы действительно хороши, поскольку я застрял над этим в течение довольно долгого времени (в жадности заставить мой код работать быстрее, чем когда-либо).
Пока заметили две вещи:
LeaveCriticalSection
если он не является владельцем указанного объекта критической секции, возникает ошибка, которая может вызвать использование другого потока EnterCriticalSection
ждать бесконечно. «)Последний подходит в тупик, который вы видите.
Если у вас есть несколько читателей одновременно, вы не контролируете, какой порядок они вызывают ReadUnlock
, так что вы не можете гарантировать, что первый поток, который является единственным разрешенным для вызова LeaveCriticalSection
является последним.
Таким образом, он не может работать правильно.
так что теперь у нас есть читатели count = 1 и работающий писатель одновременно. обратите внимание, что читатель заблокирован на EnterCriticalSection (&rwlock-> writerLock)