使用atomic实现二进制信号量

发布于 2025-01-14 18:09:40 字数 1633 浏览 2 评论 0原文

我编写此代码是为了仅使用atomic 来演示二进制信号量。

1 个线程生产者最初将向队列中推送 100 个元素。

稍后作为消费者的线程 2 和 3 将并行运行以消耗该队列。

问题是:我可以看到两个线程

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();

}

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();

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

调妓 2025-01-21 18:09:41

您在等待中有一个“间隙”:

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

load() 和 fetch_sub 本身是原子的,但在 while... load() 和 fetch_sub() 之间存在间隙。也许您应该使用“交换”(并评估结果): https:// en.cppreference.com/w/cpp/atomic/atomic/exchange 或者更好地使用compare_exchange:https://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange< /a>

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

云朵有点甜 2025-01-21 18:09:40

如果您需要对原子执行不止一项操作,则需要在数据未更改的情况下检查一致性。否则,您将有一个“差距”,正如其他答案中指出的那样。

有一个 compare_exchange 应该用于此目的:

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

现在如果< code>oldValue 已过期 oldValue 将被更新,并将执行新的检查(循环的新迭代),并在下一次迭代中再次检查条件。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文