首頁 > 軟體

C++實現一個簡易版的事件(Event)的範例程式碼

2022-11-15 14:00:13

一、前言

利用 WaitForSingleObject 檢查核心物件的狀態來進行實現。後來隨著需要開發跨平臺的程式後這種方式就不能使用了, 畢竟這是 windows 專屬。 POCO 庫在 windows之外的系統選擇利用 pthread 執行緒庫庫來實現 Event, pthread 畢竟不在C++標準庫裡面,假設要使用的話需要單獨設定。所以本文就利用 C++11之後的標準庫內容來實現一個事件類, 方便使用。

本文程式碼地址:https://github.com/pengguoqing/samples_code

二、實現

2.1 需要具備的功能

①支援多執行緒

②可以等待一定時間

2.2 程式碼實現

一共提供四個對外介面, 分別如下:

//設定事件有訊號
    inline void SetEvent()   const;
    
    //重置事件為無訊號
    inline void ResetEvent() const;
    
    //持續等待直到事件有訊號, 如果是 Auto 模式則必須等待到該執行緒能拿到狀態
    inline void Wait()       const;    
    
    //等待事件一定時間, 時間範圍內事件有訊號則返回 true,否則返回 false
    template <typename Rep, typename Period>
    inline bool tryWait(const std::chrono::duration<Rep, Period>& duratio) const;

類內部再對具體的實現進行一下封裝

struct EventImpl
	{
		explicit EventImpl(Mode mode, bool initState);
		~EventImpl() = default;
		inline void  Set();
		inline void  Reset();
		inline void  Wait();

		template <typename Rep, typename Period>
		inline bool Wait_for(const std::chrono::duration<Rep, Period>& duration);

		std::mutex				m_mutex;
		std::condition_variable m_condi;
		bool					m_signal;
		const Mode				m_mode;
	};

使用 unique_ptr 對 EventImpl 資源進行管理:

const std::shared_ptr<EventImpl> m_event;

因為沒有裸露的指標資源,移動和拷貝函數就直接全部使用編譯器預設的

explicit CXEvent(Mode mode = Mode::Auto, bool initstate = false);
~CXEvent() = default;

三、測試

測試用一個事件範例來實現兩個執行緒的同步測試, 鍵盤輸入字元 ‘s’ 觸發一次事件, 每個執行緒 Wait() 兩次事件後,再測試一下 tryWait() 時間。程式碼如下:

using namespace std;

static CXEvent kEvent;
static constexpr int testCnt = 3;

TestEventFunc1(const CXEvent& refEvent)
{
    for (int i=0; i< testCnt; i++)
    {
        
		if (i == testCnt-1)
		{
			auto begin = chrono::high_resolution_clock::now();
			kEvent.tryWait(5000ms);
			auto end = chrono::high_resolution_clock::now();
			auto duration = chrono::duration_cast<chrono::microseconds>(end - begin);
			cout << "TestEventFunc1"<<"tryWait time:"<< duration.count() << endl;
		}
		else
		{
			kEvent.Wait();
			cout << "TestEventFunc1 Wait" << endl;
		}
       
    }

}
TestEventFunc2(const CXEvent& refEvent)
{
	for (int i=0; i<testCnt; i++)
	{
		if (i == testCnt-1)
		{
			auto begin = chrono::high_resolution_clock::now();
			kEvent.tryWait(5000ms);
			auto end = chrono::high_resolution_clock::now();
			auto duration = chrono::duration_cast<chrono::microseconds>(end - begin);
			cout << "TestEventFunc2" << "tryWait time:"<< duration.count()<< endl;
		}
		else
		{
			kEvent.Wait();
			cout << "TestEventFunc2 Wait" << endl;
		}
		
	}
}

int main()
{
   	CXEvent refEvent1(kEvent);
	CXEvent refEvent2(kEvent);
    std::thread testTh1(TestEventFunc1, refEvent1);
    std::thread testTh2(TestEventFunc2, refEvent2);

	int cinCnt{0};
	char inputCmd {'R'};
	cin.get(inputCmd);
	while ('q'!=inputCmd && cinCnt<testCnt*2)
	{
		if ('s' == inputCmd)
		{
			kEvent.SetEvent();
			cinCnt++;
		}
		cin.get(inputCmd);
	}

   
	if (testTh1.joinable())
	{
		testTh1.join();
	}

	if (testTh2.joinable())
	{
		testTh2.join();
	}

	std::cout << "test set event and wait_for eventn";
}

期望結果是每輸入一次 ‘s’ 回車後,TestEventFunc1或者TestEventFunc2執行緒函數中的迴圈體就會被執行一次,每個迴圈體執行兩次後等待 5 秒執行緒就退出,再輸入‘q’ 退出程式。實際執行結果如下:

符合預期。

到此這篇關於C++實現一個簡易版的事件(Event)的範例程式碼的文章就介紹到這了,更多相關C++事件內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com