Блокировка чтения / записи с использованием только критического раздела вызывает тупик

После прохождения этот вопрос с тем же названием и его ответы, я подумал попробовать что-то, что действительно должно работать только с использованием критической секции и, следовательно, должно быть намного быстрее, чем существующие решения (которые используют другие объекты ядра, такие как мьютекс или семафор)

Вот мои функции блокировки / разблокировки чтения / записи:

#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. Для создания потоков с использованием пула потоков я использую стороннюю библиотеку. Следовательно, здесь нельзя дать весь этот код, который включает в себя множество процедур инициализации и другие вещи.

Но вкратце, я хотел бы знать, может ли кто-нибудь, взглянув на приведенный выше код, указать, что не так с этим подходом?

Я прокомментировал в коде выше, где каждый поток (из ПЯТЬ потоков) продолжает ждать, когда случится тупик. (Я узнал об этом, подключив отладчик к заблокированному процессу)

Любые входные данные / предложения были бы действительно хороши, поскольку я застрял над этим в течение довольно долгого времени (в жадности заставить мой код работать быстрее, чем когда-либо).

-1

Решение

Пока заметили две вещи:

  • Вы инициализируете критические секции в каждом потоке, что недопустимо (поведение не определено)
  • Вы не можете оставить критический раздел в другом потоке, отличном от того, в который он вошел («Если поток вызывает LeaveCriticalSection если он не является владельцем указанного объекта критической секции, возникает ошибка, которая может вызвать использование другого потока EnterCriticalSection ждать бесконечно. «)

Последний подходит в тупик, который вы видите.

Если у вас есть несколько читателей одновременно, вы не контролируете, какой порядок они вызывают ReadUnlock, так что вы не можете гарантировать, что первый поток, который является единственным разрешенным для вызова LeaveCriticalSectionявляется последним.

4

Другие решения

Таким образом, он не может работать правильно.

  • позволяет 1 потоку войти в ReadLock (), пропустить инструкцию ++, но приостановить ее перед входом в CS писателя
  • другой поток входит в WriteLock () и успешно входит в writerCS

так что теперь у нас есть читатели count = 1 и работающий писатель одновременно. обратите внимание, что читатель заблокирован на EnterCriticalSection (&rwlock-> writerLock)

0

По вопросам рекламы [email protected]