0

I want to implement a simple multi-reader/single-writer lock using a volatile value.

Although _InterlockedXXX provides full fence barrier and, if i'm right, also "volatile" keyword, I want to know about possible defects and improvements. I have no experience with acquire/release semantics.

My code:

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; 
} 

Also, if you know a library that can handle this, please tell me.

Mauro H. Leggieri
  • 1,084
  • 11
  • 25

1 Answers1

0
  • TryAcquireShared should check if *lpnValue is 0x7FFFFFFFL before increment it.
  • ReleaseShared should assert that *lpnValue doesn't have the 0x80000000L bit set rather then trying to preserve it. An exclusive lock shouldn't exist if you are releasing a shared lock.
  • TryAcquireExclusive should only check if *lpnValue is zero before setting the 0x80000000L bit.
  • Both aquire shared and aquire exclusive should have a Sleep(1) call every a certain amount of spins.
  • I don't understand the following part in TryAcquireExclusive. Why would you wait for readers if you just got an exclusive lock?

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

Rogério Ramos
  • 286
  • 1
  • 5
  • thanks for the feedback. The concept is: When a threads asks for an exclusive, the high bit is turned on so other threads requesting a any kind of access will wait. Also the thread asking for the excl. lock will wait for other threads already holding the shared lock to finish their work. About `0x7FFFFFFFL` check in first point, I didn't did the check because I assume there won't be too many readers at the same time. – Mauro H. Leggieri Sep 26 '14 at 11:11