0

I have written this code to demonstrate Binary Semaphore using only atomic .

1 thread producer will push 100 elements in the queue initially.

later threads 2 and 3 which is the consumer will run in parallel to consume this queue.

The issue is: I can see the same data/element print by both the threads

BinarySemaphore.cpp

std::queue<int> buffer;
int s_data = 1;


struct Semaphore
{
    Semaphore():s_(1)
    {

    }
    void wait()
    {
        while( s_.load() ==  0);    //you will keep waiting here until s_ becomes 1
        s_.fetch_sub(1);
    }

    void signal()
    {
        s_.fetch_add(1);
    }

    private :
    std::atomic<int> s_ ;

};

Semaphore s; 


void producer()
{
    
    while(s_data <= 100)
    {
        s.wait();

        // critical section starts
        {
            
            std::ostringstream oss;
            oss << "Consumer pushing data " << s_data <<endl;

            cout << oss.str();
            
            buffer.push(s_data++);
        }
        // critical section ends

        s.signal();
    }
}

void consumer()
{
    while (1)
    {
        s.wait();
        // critical section starts
        if (!buffer.empty())
        {
            int top = buffer.front();
            buffer.pop();

            std::ostringstream oss;
            oss << "consumer  thread id= " << this_thread::get_id() <<  " reading data = " << top  << endl;
            cout << oss.str();
        }
        // critical section ends
        s.signal();
    }
}




int main()
{
    Semaphore s;

    std::thread prod(producer);

    prod.join();

    std::thread cons1(consumer);
    std::thread cons2(consumer);


    cons1.join();
    cons2.join();

}
1
  • Sample wrong output consumer thread id= 3 reading data = 88 consumer thread id= 4 reading data = 89 consumer thread id= 3 reading data = 89 consumer thread id= 3 reading data = 90 consumer thread id= 3 reading data = 91 consumer thread id= 3 reading data = 92 consumer thread id= 3 reading data = 93 consumer thread id= 3 reading data = 94 consumer thread id= 3 reading data = 95 consumer thread id= 3 reading data = 96 consumer thread id= 4 reading data = 97 Commented Mar 15, 2022 at 12:40

2 Answers 2

3

If you need to do more then one action on atomic you need check consistency if data was not changed. Other wise you will have a "gap" as point out in other answer.

There is a compare_exchange which should be used for that:

    void wait()
    {
        auto oldValue = s_.load();
        while (oldValue == 0 || !s_.compare_exchange_strong(oldValue, oldValue - 1))
           oldValue = s_.load();
    }

Now if oldValue is out of date oldValue will be updated and new check will be performed (new iteration of loop) and in next iteration condition will be checked again.

Sign up to request clarification or add additional context in comments.

1 Comment

this logic really helped and solved my entire problem. Now when i run producer and consumer threads in parallel it works as per expectation. Thank you so much.
2

You have a "gap" in wait:

void wait()
    {
        while( s_.load() ==  0);    //you will keep waiting here until s_ becomes 1
        s_.fetch_sub(1);
    }

load() and fetch_sub are atomic by themselves but between the while... load() and fetch_sub() there is a gap. Maybe you should use "exchange" (and evaluate the result): https://en.cppreference.com/w/cpp/atomic/atomic/exchange or even better use compare_exchange: https://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange

3 Comments

With c++20 you could use wait() and notify...
thanks for pointing out this gap
@Wolfgang, that would be good advice if OP were writing production-quality code, but this example looks like a learning exercise. It looks as if OP is trying to understand how inter-thread synchronization works at the lowest levels.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.