反向信号量:一个快速的类






4.71/5 (5投票s)
实现反向信号量的类
GitHub: 这是我多线程工具的一部分:https://github.com/WindowsNT/mt
引言
你了解如何使用信号量对象,它会等待直到有人开始访问受保护的对象,最多允许一定数量的线程。
然而,通常你需要相反的功能:一种知道所有线程何时**完成**对对象操作的方法。这个快速类解决了这个问题。
注意:我希望使用标准的 C++11 实现它,但标准缺少非常有用的 **WaitForMultipleObjects**() 函数,而我们的项目需要它。
使用代码
// reverse_semaphore class reverse_semaphore { private: HANDLE hE = 0; HANDLE hM = 0; volatile unsigned long long m = 0; reverse_semaphore(const reverse_semaphore&) = delete; reverse_remaphore& 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 是为了避免竞争条件。使用此函数可确保互斥锁在所有线程释放对象之前不会被拥有。否则,该函数可能在事件设置后(即,当所有线程完成时)继续执行,但在拥有互斥锁之前,另一个线程可能会捕获该对象。
让我们测试一个示例用法
void TestRevSem() { reverse_semaphore u; vector<thread> threads; for (int i = 0; i < 10; i++) { threads.emplace_back( [&](int slp) { if (true) { std::lock_guard<UWL::reverse_semaphore> lg(u); Sleep((10 - slp) * 1000); } Sleep(5000); },i ); } // Assuming that all threads have started. Avoided extra checking for simplicity. u.Wait(); cout << "All threads released the object, threads still running"; for (auto& t : threads) t.join(); }
此示例代码创建 10 个线程,这些线程锁定反向信号量,然后在计时器上解锁它。在所有线程释放它之后,将打印一条消息。线程仍将运行另外 5 秒。
祝你好运在使用它!