65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (5投票s)

2016年1月6日

CPOL

2分钟阅读

viewsIcon

22213

实现反向信号量的类

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 秒。

祝你好运在使用它!

 

 

 

 

© . All rights reserved.