跨平台读写锁

#pragma once

#if defined(WIN32) || defined(_WIN32)
#include <Windows.h>
#else
#include <pthread.h>
#include <errno.h>

unsigned long long GetTickCount64();
#endif

class CMyEvent
{
public:
	CMyEvent(bool autoReset = true);
	~CMyEvent();

	void set();

	void wait();

	bool wait(long milliseconds);

	void reset();
private:
#if defined(WIN32) || defined(_WIN32)
	HANDLE _event;
#else
	bool            _auto;
	volatile bool   _state;
	pthread_mutex_t _mutex;
	pthread_cond_t  _cond;
#endif
};

class CMyRWLock
{
public:
	CMyRWLock();
	~CMyRWLock();

	void readLock();
	bool tryReadLock();
	void writeLock();
	bool tryWriteLock();
	void unlock();

private:
#if defined(WIN32) || defined(_WIN32)
	void addWriter();
	void removeWriter();
	unsigned long tryReadLockOnce();

	HANDLE   _mutex;
	HANDLE   _readEvent;
	HANDLE   _writeEvent;
	unsigned _readers;
	unsigned _writersWaiting;
	unsigned _writers;

#else
	pthread_rwlock_t _rwl;
#endif
};

class CMyWriteLocker
{
public:
	CMyWriteLocker(CMyRWLock *pLock):
		m_pLock(pLock)
	{
		if (m_pLock)
		{
			m_pLock->writeLock();
		}
	}
	~CMyWriteLocker()
	{
		if (m_pLock)
		{
			m_pLock->unlock();
		}
	}
private:
	CMyRWLock* m_pLock;
};

class CMyReadLocker
{
public:
	CMyReadLocker(CMyRWLock *pLock) :
		m_pLock(pLock)
	{
		if (m_pLock)
		{
			m_pLock->readLock();
		}
	}
	~CMyReadLocker()
	{
		if (m_pLock)
		{
			m_pLock->unlock();
		}
	}
private:
	CMyRWLock* m_pLock;
};
#include "CMyEvent.h"
#include "siplog.h"

#if defined(WIN32) || defined(_WIN32)

CMyEvent::CMyEvent(bool autoReset)
{
	_event = CreateEventW(NULL, autoReset ? FALSE : TRUE, FALSE, NULL);
}

CMyEvent::~CMyEvent()
{
	CloseHandle(_event);
}

void CMyEvent::set()
{
	SetEvent(_event);
}

void CMyEvent::wait()
{
	switch (WaitForSingleObject(_event, INFINITE))
	{
	case WAIT_OBJECT_0:
		return;
	default:
		return;
	}
}

bool CMyEvent::wait(long milliseconds)
{
	switch (WaitForSingleObject(_event, milliseconds + 1))
	{
	case WAIT_TIMEOUT:
		return false;
	case WAIT_OBJECT_0:
		return true;
	default:
		return false;
	}
}

void CMyEvent::reset()
{
	ResetEvent(_event);
}

#else
#include <time.h>
#include <sys/time.h>
CMyEvent::CMyEvent(bool autoReset) : _auto(autoReset), _state(false)
{
	if (pthread_mutex_init(&_mutex, NULL))
		ERROR_LOG("cannot create event (mutex)");

	if (pthread_cond_init(&_cond, NULL))
	{
		pthread_mutex_destroy(&_mutex);
		ERROR_LOG("cannot create event (condition)");
	}
}

CMyEvent::~CMyEvent()
{
	pthread_cond_destroy(&_cond);
	pthread_mutex_destroy(&_mutex);
}

void CMyEvent::set()
{
	if (pthread_mutex_lock(&_mutex))
		ERROR_LOG("cannot signal event(lock)");
	_state = true;
	if (pthread_cond_broadcast(&_cond))
	{
		pthread_mutex_unlock(&_mutex);
		ERROR_LOG("cannot signal event");
	}
	pthread_mutex_unlock(&_mutex);
}

void CMyEvent::wait()
{
	if (pthread_mutex_lock(&_mutex))
		ERROR_LOG("wait for event failed (lock)");
	while (!_state)
	{
		if (pthread_cond_wait(&_cond, &_mutex))
		{
			pthread_mutex_unlock(&_mutex);
			ERROR_LOG("wait for event failed");
		}
	}
	if (_auto)
		_state = false;
	pthread_mutex_unlock(&_mutex);
}

bool CMyEvent::wait(long milliseconds)
{
	int rc = 0;
	struct timespec abstime;

	struct timeval tv;
	gettimeofday(&tv, NULL);
	abstime.tv_sec = tv.tv_sec + milliseconds / 1000;
	abstime.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;
	if (abstime.tv_nsec >= 1000000000)
	{
		abstime.tv_nsec -= 1000000000;
		abstime.tv_sec++;
	}

	if (pthread_mutex_lock(&_mutex) != 0)
		ERROR_LOG("wait for event failed (lock)");
	while (!_state)
	{
		if ((rc = pthread_cond_timedwait(&_cond, &_mutex, &abstime)))
		{
			if (rc == ETIMEDOUT) break;
			pthread_mutex_unlock(&_mutex);
			ERROR_LOG("cannot wait for event");
		}
	}
	if (rc == 0 && _auto) _state = false;
	pthread_mutex_unlock(&_mutex);
	return rc == 0;
}

void CMyEvent::reset()
{
	if (pthread_mutex_lock(&_mutex))
		ERROR_LOG("cannot reset event");
	_state = false;
	pthread_mutex_unlock(&_mutex);
}

#endif

#if defined(WIN32) || defined(_WIN32)

CMyRWLock::CMyRWLock() : _readers(0), _writersWaiting(0), _writers(0)
{
	_mutex = CreateMutexW(NULL, FALSE, NULL);
	if (_mutex == NULL)
		return;

	_readEvent = CreateEventW(NULL, TRUE, TRUE, NULL);
	if (_readEvent == NULL)
		return;

	_writeEvent = CreateEventW(NULL, TRUE, TRUE, NULL);
	if (_writeEvent == NULL)
		return;
}

CMyRWLock::~CMyRWLock()
{
	CloseHandle(_mutex);
	CloseHandle(_readEvent);
	CloseHandle(_writeEvent);
}

void CMyRWLock::readLock()
{
	HANDLE h[2];
	h[0] = _mutex;
	h[1] = _readEvent;
	switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
	{
	case WAIT_OBJECT_0:
	case WAIT_OBJECT_0 + 1:
		++_readers;
		ResetEvent(_writeEvent);
		ReleaseMutex(_mutex);
		break;
	default:
		break;;
	}
}

bool CMyRWLock::tryReadLock()
{
	for (;;)
	{
		if (_writers != 0 || _writersWaiting != 0)
			return false;

		DWORD result = tryReadLockOnce();
		switch (result)
		{
		case WAIT_OBJECT_0:
		case WAIT_OBJECT_0 + 1:
			return true;
		case WAIT_TIMEOUT:
			continue; // try again
		default:
			return false;
		}
	}
}

void CMyRWLock::writeLock()
{
	addWriter();
	HANDLE h[2];
	h[0] = _mutex;
	h[1] = _writeEvent;
	switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))
	{
	case WAIT_OBJECT_0:
	case WAIT_OBJECT_0 + 1:
		--_writersWaiting;
		++_readers;
		++_writers;
		ResetEvent(_readEvent);
		ResetEvent(_writeEvent);
		ReleaseMutex(_mutex);
		break;
	default:
		removeWriter();
		break;
	}
}

bool CMyRWLock::tryWriteLock()
{
	addWriter();
	HANDLE h[2];
	h[0] = _mutex;
	h[1] = _writeEvent;
	switch (WaitForMultipleObjects(2, h, TRUE, 1))
	{
	case WAIT_OBJECT_0:
	case WAIT_OBJECT_0 + 1:
		--_writersWaiting;
		++_readers;
		++_writers;
		ResetEvent(_readEvent);
		ResetEvent(_writeEvent);
		ReleaseMutex(_mutex);
		return true;
	case WAIT_TIMEOUT:
		removeWriter();
		return false;
	default:
		removeWriter();
		break;
	}
	return false;
}

void CMyRWLock::unlock()
{
	switch (WaitForSingleObject(_mutex, INFINITE))
	{
	case WAIT_OBJECT_0:
		_writers = 0;
		if (_writersWaiting == 0) SetEvent(_readEvent);
		if (--_readers == 0) SetEvent(_writeEvent);
		ReleaseMutex(_mutex);
		break;
	default:
		break;
	}
}

void CMyRWLock::addWriter()
{
	switch (WaitForSingleObject(_mutex, INFINITE))
	{
	case WAIT_OBJECT_0:
		if (++_writersWaiting == 1) ResetEvent(_readEvent);
		ReleaseMutex(_mutex);
		break;
	default:
		break;;
	}
}

void CMyRWLock::removeWriter()
{
	switch (WaitForSingleObject(_mutex, INFINITE))
	{
	case WAIT_OBJECT_0:
		if (--_writersWaiting == 0 && _writers == 0) SetEvent(_readEvent);
		ReleaseMutex(_mutex);
		break;
	default:
		break;
	}
}

unsigned long CMyRWLock::tryReadLockOnce()
{
	HANDLE h[2];
	h[0] = _mutex;
	h[1] = _readEvent;
	DWORD result = WaitForMultipleObjects(2, h, TRUE, 1);
	switch (result)
	{
	case WAIT_OBJECT_0:
	case WAIT_OBJECT_0 + 1:
		++_readers;
		ResetEvent(_writeEvent);
		ReleaseMutex(_mutex);
		return result;
	case WAIT_TIMEOUT:
		return result;
	default:
		break;;
	}
	return false;
}

#else

unsigned long long GetTickCount64()
{
	struct timespec ts;
	clock_gettime(CLOCK_MONOTONIC, &ts);
	return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}

CMyRWLock::CMyRWLock()
{
	if (pthread_rwlock_init(&_rwl, NULL))
		ERROR_LOG("cannot create reader/writer lock\n");
}

CMyRWLock::~CMyRWLock()
{
	pthread_rwlock_destroy(&_rwl);
}

void CMyRWLock::readLock()
{
	if (pthread_rwlock_rdlock(&_rwl))
		ERROR_LOG("cannot lock reader/writer lock\n");
}

bool CMyRWLock::tryReadLock()
{
	int rc = pthread_rwlock_tryrdlock(&_rwl);
	if (rc == 0)
		return true;
	else if (rc == EBUSY)
		return false;
	else
		ERROR_LOG("cannot lock reader/writer lock\n");
	return false;
}

void CMyRWLock::writeLock()
{
	if (pthread_rwlock_wrlock(&_rwl))
		ERROR_LOG("cannot lock reader/writer lock\n");
}

bool CMyRWLock::tryWriteLock()
{
	int rc = pthread_rwlock_trywrlock(&_rwl);
	if (rc == 0)
		return true;
	else if (rc == EBUSY)
		return false;
	else
		ERROR_LOG("cannot lock reader/writer lock\n");
	return false;
}

void CMyRWLock::unlock()
{
	if (pthread_rwlock_unlock(&_rwl))
		ERROR_LOG("cannot unlock mutex\n");
}

#endif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值