Click here to Skip to main content
13,558,615 members
Click here to Skip to main content
Add your own
alternative version

Stats

8K views
3 bookmarked
Posted 6 Jan 2016
Licenced CPOL

Reverse Semaphore : A quick class

, 24 Apr 2016
Rate this:
Please Sign up or sign in to vote.
A class to implement a reverse semaphore

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)

Share

About the Author

Michael Chourdakis
Engineer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS and Android.

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

My home page: http://www.michaelchourdakis.com

You may also be interested in...

Comments and Discussions

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

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03-2016 | 2.8.180515.1 | Last Updated 24 Apr 2016
Article Copyright 2016 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid