2013-09-27 2 views
0

Я хочу реализовать простой замок с несколькими считывателями/одиночными писателями, используя изменчивое значение.Программа ReaderWriter Lock-free

Хотя _InterlockedXXX обеспечивает полный барьер ограждения и, если я прав, также «изменчивое» ключевое слово, я хочу знать о возможных дефектах и ​​улучшениях. У меня нет опыта семантики получения/выпуска.

Мой код:

BOOL TryAcquireShared(LONG volatile *lpnValue) 
{ 
    LONG initVal; 

    do 
    { 
    initVal = *lpnValue; 
    if (initVal == 0x80000000L) 
     return FALSE; //a writer is active 
    } 
    while (_InterlockedCompareExchange(lpnValue, initVal+1, initVal) != initVal); 
    return TRUE; 
} 

VOID ReleaseShared(LONG volatile *lpnValue) 
{ 
    LONG initVal, newVal; 

    do 
    { 
    initVal = *lpnValue; 
    newVal = (initVal & 0x80000000L) | ((initVal & 0x7FFFFFFFL) - 1); 
    } 
    while (_InterlockedCompareExchange(lpnValue, newVal, initVal) != initVal); 
    return; 
} 

BOOL TryAcquireExclusive(LONG volatile *lpnValue) 
{ 
    LONG i, initVal, newVal; 

    do 
    { 
    initVal = *lpnValue; 
    if ((initVal & 0x80000000L) != 0) 
     return FALSE; //another writer is active or waiting 
    } 
    while (_InterlockedCompareExchange(lpnValue, initVal | 0x80000000L, initVal) != initVal); 
    //wait until no readers 
    while ((*lpnValue & 0x7FFFFFFFL) != 0) 
    ::Sleep(1); 
    return TRUE; 
} 

VOID ReleaseExclusive(LONG volatile *lpnValue) 
{ 
    _InterlockedExchange(lpnValue, 0); 
    return; 
} 

Кроме того, если вы знаете, библиотека, которая может справиться с этим, пожалуйста, сообщите мне.

ответ

0
  • TryAcquireShared должен проверить, если * lpnValue равен 0x7FFFFFFFL, прежде чем увеличивать его.
  • ReleaseShared должен утверждать, что * lpnValue не имеет установленного бита 0x80000000L, а затем пытается его сохранить. Эксклюзивная блокировка не должна существовать, если вы освобождаете общую блокировку.
  • TryAcquireExclusive должен только проверить, если * lpnValue равен нулю перед установкой бит 0x80000000L.
  • В обоих вариантах aquire shared и aquire должен быть поспать (1) на каждое определенное количество вращений.
  • Я не понимаю следующую часть в TryAcquireExclusive. Зачем вам ждать читателей, если у вас есть эксклюзивный замок?

    while ((* lpnValue & 0x7FFFFFFFL)! = 0) :: Sleep (1);

+0

благодарит за отзыв. Концепция такова: когда потоки запрашивают эксклюзив, высокий бит включается, поэтому другие потоки, запрашивающие какой-либо доступ, будут ждать. Также поток, запрашивающий исключение. блокировка будет ждать, пока другие потоки, уже имеющие общий замок, не закончат свою работу. О '0x7FFFFFFFL' проверяет первую точку, я не делал чек, потому что предполагаю, что не будет слишком много читателей одновременно. –