我写了一个递归锁,它的行为喜欢临界区。但是当我实现递归功能时我遇到了问题。像这样的代码:
#include "own_cs.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <assert.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
struct own_critical_section
{
long own_lock_count; // count of locked thread, -1 means unlock , other means lock.
HANDLE own_event; // auto-reset
DWORD own_owning_thread_id; // owner thread of lock
};
void InitialOwnCriticalSection( own_critical_section** own_cs)
{
*own_cs = (own_critical_section*)malloc( sizeof( own_critical_section ) );
(*own_cs)->own_lock_count = -1;
(*own_cs)->own_event = CreateEventW( NULL, FALSE, FALSE, NULL );
(*own_cs)->own_owning_thread_id = 0;
}
void DeleteOwnCriticalSection( own_critical_section* own_cs )
{
assert( own_cs != NULL );
CloseHandle( own_cs->own_event );
free( own_cs );
}
void EnterOwnCriticalSection( own_critical_section* own_cs )
{
for ( int spin_count = 0; spin_count < 500; ++ spin_count )
{//spinlock
if ( -1L == InterlockedCompareExchange( &own_cs->own_lock_count, -1L, -1L ) )
break;
Sleep(0);
}
if( 0 < InterlockedIncrement( &own_cs->own_lock_count ) &&
( own_cs->own_owning_thread_id != ::GetCurrentThreadId() ) )
//there is no guarantee that own_owning_thread_id is set before comparison with tid.so this comparison is not thread-safe.
{
//locked
WaitForSingleObject( own_cs->own_event, INFINITE );
}
own_cs->own_owning_thread_id = ::GetCurrentThreadId();
}
void LeaveOwnCriticalSection( own_critical_section* own_cs )
{
if( -1L != InterlockedDecrement( &own_cs->own_lock_count ) &&
(::GetCurrentThreadId() == own_cs->own_owning_thread_id ) )
{
SetEvent( own_cs->own_event );
}
}
问题是 EnterOwnCriticalSection 例程;作为该函数中的注释,不保证在与 tid 比较之前设置 own_owning_thread_id。所以这种比较不是线程安全的。