Click here to Skip to main content
15,881,803 members
Articles / Desktop Programming / Win32

Reverse Semaphore : A quick class

Rate me:
Please Sign up or sign in to vote.
4.71/5 (5 votes)
24 Apr 2016CPOL2 min read 20.6K   5   10
A class to implement a reverse semaphore

GitHub: Part of my Multithreading tools: https://github.com/WindowsNT/mt

Introduction

You know how to use semaphore objects, which wait until someone starts accessing a protected object and up to a maximum number of threads.

However, very often you need the opposite: A way to know when all threads are finished with an object. This is a quick class that resolves this problem.

Note: I 'd love to implement it with standard C++ 11, but the standard lacks the very useful WaitForMultipleObjects() which is needed in our project.

Using the code

 

    // 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;
                }


        };

 

Constructor/Destructor

Creates one mutex and one event for our work. Copying the class is not allowed. The destructor releases these objects.

lock()

Atomically increases usage counter by 1.

unlock()

Atomically decreases usage couter by 1. If this counter reaches 0, the event is set.

Wait()

Waits for the event. The event is set when all threads that have captured the object have released it. 

WaitAndLock()

Waits for both the event and the mutex, ensuring that after all threads have finished with the object it is recaptured by the current thread. This is the function you will use most.

WaitAndBlock()

Waits for both the event and the mutex, ensuring that after all threads have finished with the object,no other thread can capture the object. The function returns the handle of the locked mutex, which should be released later with ReleaseMutex() after the calling thread finishes it's exclusive access to the object.
 
The use of WaitForMultipleObjects is required to avoid a race condition. Using this function ensures that the mutex is not owned until all threads have released the object. Without it, the function could be able to continue after the event was set (i.e. when all threads were finished) but, before owning the mutex, another thread might capture the object.
 
 
Let us test an example usage:
 
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();
    }

This sample code creates 10 threads that lock the reverse semaphore, then unlock it on a timer. After all threads have released it, a message is printed. The threads still run for 5 more seconds.

Good luck in using it!

 

 

 

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS, Android and Web (HTML/Javascript/CSS).

I 've a PhD in Digital Signal Processing and Artificial Intelligence and I specialize in Pro Audio and AI applications.

My home page: https://www.turbo-play.com

Comments and Discussions

 
QuestionNot atomic Pin
feanorgem7-Jan-16 13:50
feanorgem7-Jan-16 13:50 
Suggestionthere is nothing about this class that is portable Pin
vickoza7-Jan-16 11:09
vickoza7-Jan-16 11:09 
GeneralRe: there is nothing about this class that is portable Pin
Michael Chourdakis7-Jan-16 11:12
mvaMichael Chourdakis7-Jan-16 11:12 
QuestionComments Pin
William E. Kempf6-Jan-16 7:39
William E. Kempf6-Jan-16 7:39 
AnswerRe: Comments Pin
Michael Chourdakis6-Jan-16 7:44
mvaMichael Chourdakis6-Jan-16 7:44 
GeneralRe: Comments Pin
William E. Kempf6-Jan-16 8:22
William E. Kempf6-Jan-16 8:22 
GeneralRe: Comments Pin
Michael Chourdakis6-Jan-16 8:24
mvaMichael Chourdakis6-Jan-16 8:24 
GeneralRe: Comments Pin
William E. Kempf6-Jan-16 9:36
William E. Kempf6-Jan-16 9:36 
GeneralRe: Comments Pin
Michael Chourdakis6-Jan-16 9:46
mvaMichael Chourdakis6-Jan-16 9:46 
GeneralRe: Comments Pin
William E. Kempf6-Jan-16 10:06
William E. Kempf6-Jan-16 10:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.