0

我想使用 volatile 值实现一个简单的多读/单写锁。

虽然 _InterlockedXXX 提供了完整的栅栏屏障,如果我是对的,还有“volatile”关键字,我想知道可能的缺陷和改进。我没有获取/释放语义的经验。

我的代码:

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

另外,如果您知道可以处理此问题的图书馆,请告诉我。

4

1 回答 1

0
  • TryAcquireShared 应该在增加它之前检查 *lpnValue 是否为 0x7FFFFFFFL。
  • ReleaseShared 应该断言 *lpnValue 没有设置 0x80000000L 位,而不是尝试保留它。如果您要释放共享锁,则不应存在独占锁。
  • TryAcquireExclusive 只应在设置 0x80000000L 位之前检查 *lpnValue 是否为零。
  • aquire shared 和 aquire exclusive 都应该在每旋转一定量时调用 Sleep(1)。
  • 我不理解 TryAcquireExclusive 中的以下部分。如果您只是获得了排他锁,为什么还要等待读者?

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

于 2014-09-26T05:39:13.060 回答