一個跨平臺的線程讀寫鎖
不廢話,直接上代碼:
/***********************************************************************
* Copyright (c) 2008-2080 [email protected]
*
* ALL RIGHTS RESERVED.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**********************************************************************/
/**
* @filename thread_swlock.h
* thread safe lock for both Windows and Linux.
*
* @author Liang Zhang <[email protected]>
* @version 0.0.1
* @create 2019-11-14
* @update 2019-11-14
*/
#ifndef THREAD_SWLOCK_H_INCLUDED
#define THREAD_SWLOCK_H_INCLUDED
#if defined(__cplusplus)
extern "C"
{
#endif
#if defined(_WIN32)
# include <synchapi.h>
/* SRWLock functions */
typedef void(CALLBACK *LPFN_SRWLOCK_API)(PSRWLOCK);
typedef BOOLEAN(CALLBACK *LPFN_SRWLOCK_TRYAPI)(PSRWLOCK);
typedef BOOL(CALLBACK *LPFN_SRWLOCK_SLEEPAPI)(PCONDITION_VARIABLE, PSRWLOCK, DWORD, ULONG);
/* Critical section functions */
typedef void(CALLBACK *LPFN_CRITSEC_API)(LPCRITICAL_SECTION);
typedef BOOL(CALLBACK *LPFN_CRITSEC_TRYAPI)(LPCRITICAL_SECTION);
#else
# include<pthread.h>
/* https://linux.die.net/man/3/pthread_rwlock_wrlock */
#endif
typedef struct _ThreadLock_t
{
#if defined(_WIN32)
/**
* SRWLock functions - vs2005 and after
*
* synchapi.h(include Windows 7, Windows Server 2008 Windows Server 2008 R2, Windows.h)
* https://docs.microsoft.com/en-us/windows/win32/sync/slim-reader-writer--srw--locks
* https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initializesrwlock
*
* Exclusive for Write, Shared for Read
*/
SRWLOCK srwLock;
LPFN_SRWLOCK_API lpfnInitializeSRWLock;
LPFN_SRWLOCK_API lpfnAcquireSRWLockExclusive;
LPFN_SRWLOCK_API lpfnAcquireSRWLockShared;
LPFN_SRWLOCK_API lpfnReleaseSRWLockExclusive;
LPFN_SRWLOCK_API lpfnReleaseSRWLockShared;
LPFN_SRWLOCK_TRYAPI lpfnTryAcquireSRWLockExclusive;
LPFN_SRWLOCK_TRYAPI lpfnTryAcquireSRWLockShared;
LPFN_SRWLOCK_SLEEPAPI lpfnSleepConditionVariableSRW;
/* Critical section functions */
CRITICAL_SECTION critSec;
LPFN_CRITSEC_API lpfnInitializeCriticalSection;
LPFN_CRITSEC_API lpfnDeleteCriticalSection;
LPFN_CRITSEC_API lpfnEnterCriticalSection;
LPFN_CRITSEC_API lpfnLeaveCriticalSection;
LPFN_CRITSEC_TRYAPI lpfnTryEnterCriticalSection;
#else
/* Linux */
pthread_rwlock_t rwlock;
#endif
} ThreadLock_t;
static void ThreadLockInit (ThreadLock_t *lock)
{
memset(lock, 0, sizeof(*lock));
#if defined(_WIN32)
HMODULE hModule = GetModuleHandle("kernel32.dll");
if (hModule) {
lock->lpfnInitializeSRWLock = (LPFN_SRWLOCK_API) GetProcAddress(hModule, "InitializeSRWLock");
if (lock->lpfnInitializeSRWLock) {
lock->lpfnAcquireSRWLockExclusive = (LPFN_SRWLOCK_API) GetProcAddress(hModule, "AcquireSRWLockExclusive");
lock->lpfnAcquireSRWLockShared = (LPFN_SRWLOCK_API) GetProcAddress(hModule, "AcquireSRWLockShared");
lock->lpfnReleaseSRWLockExclusive = (LPFN_SRWLOCK_API) GetProcAddress(hModule, "ReleaseSRWLockExclusive");
lock->lpfnReleaseSRWLockShared = (LPFN_SRWLOCK_API) GetProcAddress(hModule, "ReleaseSRWLockShared");
lock->lpfnTryAcquireSRWLockExclusive = (LPFN_SRWLOCK_TRYAPI) GetProcAddress(hModule, "TryAcquireSRWLockExclusive");
lock->lpfnTryAcquireSRWLockShared = (LPFN_SRWLOCK_TRYAPI) GetProcAddress(hModule, "TryAcquireSRWLockShared");
lock->lpfnSleepConditionVariableSRW = (LPFN_SRWLOCK_SLEEPAPI) GetProcAddress(hModule, "SleepConditionVariableSRW");
}
else {
lock->lpfnInitializeCriticalSection = (LPFN_CRITSEC_API) GetProcAddress(hModule, "InitializeCriticalSection");
lock->lpfnDeleteCriticalSection = (LPFN_CRITSEC_API) GetProcAddress(hModule, "DeleteCriticalSection");
lock->lpfnEnterCriticalSection = (LPFN_CRITSEC_API) GetProcAddress(hModule, "EnterCriticalSection");
lock->lpfnLeaveCriticalSection = (LPFN_CRITSEC_API) GetProcAddress(hModule, "LeaveCriticalSection");
lock->lpfnTryEnterCriticalSection = (LPFN_CRITSEC_TRYAPI) GetProcAddress(hModule, "TryEnterCriticalSection");
}
}
if (lock->lpfnInitializeSRWLock) {
lock->lpfnInitializeSRWLock(&lock->srwLock);
}
else {
lock->lpfnInitializeCriticalSection(&lock->critSec);
}
#else
// Linux
if (pthread_rwlock_init(&lock->rwlock, NULL) != 0) {
exit(EXIT_FAILURE);
}
#endif
}
static void ThreadLockUninit(ThreadLock_t *lock)
{
#if defined(_WIN32)
if (lock->lpfnDeleteCriticalSection) {
lock->lpfnDeleteCriticalSection(&lock->critSec);
}
#else
// Linux
pthread_rwlock_destroy(&lock->rwlock);
#endif
}
static int ThreadLockAcquire(ThreadLock_t *lock, int writeState, int tryBool)
{
// success
int err = 0;
#if defined(_WIN32)
if (writeState) {
if (tryBool) {
if (lock->lpfnTryAcquireSRWLockExclusive) {
if (!lock->lpfnTryAcquireSRWLockExclusive(&lock->srwLock)) {
err = 1;
}
}
else {
if (!lock->lpfnTryEnterCriticalSection(&lock->critSec)) {
err = 1;
}
}
}
else {
if (lock->lpfnAcquireSRWLockExclusive) {
lock->lpfnAcquireSRWLockExclusive(&lock->srwLock);
}
else {
lock->lpfnEnterCriticalSection(&lock->critSec);
}
}
}
else {
if (tryBool) {
if (lock->lpfnTryAcquireSRWLockShared) {
if (!lock->lpfnTryAcquireSRWLockShared(&lock->srwLock)) {
err = 1;
}
}
else {
if (!lock->lpfnTryEnterCriticalSection(&lock->critSec)) {
err = 1;
}
}
}
else {
if (lock->lpfnAcquireSRWLockShared) {
lock->lpfnAcquireSRWLockShared(&lock->srwLock);
}
else {
lock->lpfnEnterCriticalSection(&lock->critSec);
}
}
}
#else
// Linux
if (writeState) {
if (tryBool) {
err = pthread_rwlock_trywrlock(&lock->rwlock);
}
else {
err = pthread_rwlock_wrlock(&lock->rwlock);
}
}
else {
if (tryBool) {
err = pthread_rwlock_tryrdlock(&lock->rwlock);
}
else {
err = pthread_rwlock_rdlock(&lock->rwlock);
}
}
#endif
// Linux: If successful, shall return zero;
// otherwise, an error number shall be returned to indicate the error.
//
// Windows:
// if tryBool is 0, always success with returned zero;
// if tryBool not 0, returns non-zero(1) indicates error.
return err;
}
static int ThreadLockRelease(ThreadLock_t *lock, int writeState)
{
int err = 0;
#if defined(_WIN32)
if (writeState) {
if (lock->lpfnReleaseSRWLockExclusive) {
lock->lpfnReleaseSRWLockExclusive(&lock->srwLock);
}
else {
lock->lpfnLeaveCriticalSection(&lock->critSec);
}
}
else {
if (lock->lpfnReleaseSRWLockShared) {
lock->lpfnReleaseSRWLockShared(&lock->srwLock);
}
else {
lock->lpfnLeaveCriticalSection(&lock->critSec);
}
}
#else
// Linux
err = pthread_rwlock_unlock(&lock->rwlock);
#endif
// Linux: If successful, shall return zero;
// otherwise, an error number shall be returned to indicate the error.
//
// Windows: always success with returned zero;
return err;
}
#if defined(__cplusplus)
}
#endif
#endif /* THREAD_SWLOCK_H_INCLUDED */