C++线程同步:反向信号量的使用

多线程编程中,经常需要一种机制来同步线程,以确保在访问共享资源时不会发生冲突。通常,会使用信号量(semaphore)对象来等待某个线程开始访问受保护的对象,并允许一定数量的线程同时访问。然而,有时候需要相反的功能:一种方法来知道所有线程何时完成了对某个对象的访问。本文将介绍一个简单的类,用于解决这个问题。

注意:作者更倾向于使用标准的C++11实现,但标准库中缺少了项目中需要的非常有用的WaitForMultipleObjects()函数。

反向信号量类

反向信号量类通过创建互斥量(mutex)和事件(event)来实现线程同步。以下是该类的实现:

class reverse_semaphore { private: HANDLE hE = 0; HANDLE hM = 0; volatile unsigned long long m = 0; reverse_semaphore(const reverse_semaphore&) = delete; reverse_semaphore& operator=(const reverse_semaphore&) = delete; public: reverse_semaphore() { m = 0; hE = CreateEvent(0, TRUE, TRUE, 0); hM = CreateMutex(0, 0, 0); } ~reverse_semaphore() { CloseHandle(hM); hM = 0; CloseHandle(hE); hE = 0; } void lock() { WaitForSingleObject(hM, INFINITE); m++; ResetEvent(hE); ReleaseMutex(hM); } void unlock() { WaitForSingleObject(hM, INFINITE); if(m > 0) m--; if(m == 0) SetEvent(hE); ReleaseMutex(hM); } DWORD Wait(DWORD dw = INFINITE) { return WaitForSingleObject(hE, dw); } void WaitAndLock() { HANDLE h[2] = {hE, hM}; WaitForMultipleObjects(2, h, TRUE, INFINITE); lock(); ReleaseMutex(hM); } HANDLE WaitAndBlock() { HANDLE h[2] = {hE, hM}; WaitForMultipleObjects(2, h, TRUE, INFINITE); return hM; } };

构造函数/析构函数:创建一个互斥量和一个事件用于工作。不允许复制该类。析构函数释放这些对象。

lock():原子地将使用计数器增加1。

unlock():原子地将使用计数器减少1。如果计数器达到0,则设置事件

Wait():等待事件。当所有捕获对象的线程都释放了它时,事件被设置。

WaitAndLock():等待事件和互斥量,确保所有线程完成对对象的操作后,当前线程重新捕获它。这是最常用的函数。

WaitAndBlock():等待事件和互斥量,确保所有线程完成对对象的操作后,没有其他线程可以捕获对象。函数返回锁定的互斥量的句柄,调用线程在其独占访问对象完成后应使用ReleaseMutex()释放它。

使用WaitForMultipleObjects()是为了避免竞态条件。使用这个函数确保在所有线程释放对象之前,互斥量不会被拥有。如果没有它,函数可能在事件被设置后(即所有线程都完成时)继续执行,但在拥有互斥量之前,另一个线程可能捕获了对象。

示例用法

以下是一个示例代码,创建10个线程锁定反向信号量,然后在计时器上解锁它。所有线程释放它后,打印一条消息。线程仍然运行5秒钟。

void TestRevSem() { reverse_semaphore u; vector threads; for (int i = 0; i < 10; i++) { threads.emplace_back([&](int slp) { if (true) { std::lock_guard lg(u); Sleep((10 - slp) * 1000); } Sleep(5000); }, i); } // 假设所有线程都已启动。为简单起见,避免额外检查。 u.Wait(); cout << "All threads released the object, threads still running"; for (auto& t : threads) t.join(); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485