From: Thomas P. <tp...@gm...> - 2003-11-20 12:22:18
|
Your version of TryEnterCriticalSection : /* Our own version of TryEnterCriticalSection since it is not available * on Windows 9x. */ static inline BOOL __TryEnterCriticalSection (LPCRITICAL_SECTION lpCriticalSection) { HANDLE hThreadId = (HANDLE) GetCurrentThreadId(); if (InterlockedIncrement(&lpCriticalSection->LockCount) == 0) { lpCriticalSection->OwningThread = hThreadId; lpCriticalSection->RecursionCount = 1; } else { if (lpCriticalSection->OwningThread == hThreadId) lpCriticalSection->RecursionCount++; { InterlockedDecrement(&lpCriticalSection->LockCount); return FALSE; } return TRUE; } has a race condition. If the mutex is locked and a task switch occurs between InterlockedIncrement and InterlockedDecrement and the mutex is unlocked during that time then the counter contains an invalid (still incremented) value and the unlock function assumes that another thread is waiting on that mutex. And i do not think that critical section internals should be used here. The mutex logic which is used by pthreads-win32 and cygwin is similar to a critical section: struct mutex { LONG counter; HANDLE sema; }; mx_init (struct mutex *mx) { mx->counter = 0; mx->sema = CreateSemaphore (NULL, 0, LONG_MAX, NULL); } int mx_lock (struct mutex *mx) { if (InterlockedIncrement (&mx->counter) != 1) WaitForSingleObject (mx->sema, INFINITE); return 0; } int mx_trylock (struct mutex *mx) { if (InterlockedCompareExchange (&mx->counter, 1, 0 ) != 0) return 1; return 0; } int mx_unlock (struct mutex *mx) { if (InterlockedDecrement (&mx->counter)) ReleaseSemaphore (mx->sema, 1, NULL); return 0; } A return value of 0 signals success. This code will run on Win98 and NT4 or above. Win95 and NT3 are designed to run on a i386 and does not contain an InterlockedCompareExchange and the Interlocked[Increment|Decrement] are not thread safe. Cygwin avoids this by using inline assembler replacements for Interlocked[Increment|Decrement|CompareExchange] that are based on xadd and cmpxchg which requires at least on i486. The above implements a fast (deadlocking and not errorchecking) mutex. I think that this is enough for gcc since this is also the default on Linux. Regards, Thomas |