1. 程式人生 > >將Linux的訊號量sem_t封裝成事件物件

將Linux的訊號量sem_t封裝成事件物件

    將訊號量sem_t相關的一組API封裝成Win32平臺上的事件物件類之後,在Linux平臺上就可以像使用事件物件那樣,方便地進行執行緒同步了。

class CEventImpl
{
protected:
	
	/*
	 建立匿名訊號量
	`bAutoReset  true   人工重置
				 false  自動重置
	*/
	CEventImpl(bool manualReset);		
	
	/*
	 登出訊號量
	*/
	~CEventImpl();

	/*
	 將當前事件物件設定為有訊號狀態
	 若自動重置,則等待該事件物件的所有執行緒只有一個可被排程
	 若人工重置,則等待該事件物件的所有執行緒變為可被排程
	*/
	void SetImpl();

	/*
	 以當前事件物件,阻塞執行緒,將其永遠掛起
	 直到事件物件被設定為有訊號狀態
	*/
	bool WaitImpl();

	/*
	 以當前事件物件,阻塞執行緒,將其掛起指定時間間隔
	 之後執行緒自動恢復可排程
	*/
	bool WaitImpl(long milliseconds);

	/*
	 將當前事件物件設定為無訊號狀態
	*/
	void ResetImpl();

private:
	bool        m_manual;
	sem_t		m_event;
};

inline void CEventImpl::SetImpl()
{
	int ret = sem_post(&m_event);
	if ( 0 != ret )
	{
		cout<<"cannot signal event"<<endl;
	}
}

inline void CEventImpl::ResetImpl()
{
	int sval = 0;
	do 
	{
		sem_trywait(&m_event);
		sem_getvalue(&m_event, &sval);
	} while(sval > 0);
}
CEventImpl::CEventImpl(bool manualReset): m_manual(manualReset)
{
	unsigned int nValue = 0; //初始化為無訊號
	int ret = sem_init(&m_event, 0, nValue);
	if ( 0 != ret )
	{
		cout<<"sem_init failed"<<endl; 
	}
}

CEventImpl::~CEventImpl()
{
	sem_destroy(&m_event);
}

bool CEventImpl::WaitImpl()
{
	int ret = sem_wait(&m_event);
	if ( 0 != ret )
	{
		cout<<"CEventImpl::WaitImpl sem_wait failed"<<endl; 
	}

	if ( m_manual )
	{
		sem_post(&m_event);
	}

	return true;
}

bool CEventImpl::WaitImpl(long milliseconds)
{
	if ( 0 == milliseconds )
	{
		int ret = sem_trywait(&m_event);
		if ( 0 == ret )
		{
			if ( m_manual )
			{
				sem_post(&m_event);
			}
		}
	}
	else
	{
		int roopMax = milliseconds/10;
		do 
		{
			usleep(10*1000);
			int ret = sem_trywait(&m_event);
			if ( 0 == ret )
			{
				if ( m_manual )
				{
					sem_post(&m_event);
				}

				break;
			}

			roopMax--;
		} while( roopMax > 0 );
	}

	return true;
}

    類CEventImpl