【问题标题】:C++11 multiple read and one write thread mutex [duplicate]C ++ 11多读一写线程互斥体[重复]
【发布时间】:2013-11-11 20:19:20
【问题描述】:

我有一个应用程序,其中一些 STL 容器在 3 个线程中读取,并在 2 个线程中写入。我知道多线程容器有 TBB,但它不是我的应用程序中的选项。

所以我想使用 std::mutex 和我的双手使程序线程安全。这是我所做的一个简单版本:

int readers = 0;
std::mutex write;

// One write, no reads.
void write_fun()
{
    write.lock();// We lock the resource
    while(readers > 0){}// We wait till everyone finishes read.
    // DO WRITE
    write.unlock();// Release
}

// Multiple reads, no write
void read_fun()
{
    // We wait if it is being written.
    while(!write.try_lock()){}
    write.unlock();

    readers++;
    // do read
    readers--;
}

这是在 C++11 中执行此操作的正确方法吗?

【问题讨论】:

    标签: c++ multithreading c++11


    【解决方案1】:

    非常接近,需要注意的几件事,在 c++ 中为了异常安全和可读性,IMO,使用 RAII 锁很好。您真正需要的是一个 shared_mutex,例如 boost 或 c++14 中的。

    std::shared_mutex write; //use boost's or c++14 
    
    // One write, no reads.
    void write_fun()
    {
        std::lock_guard<std::shared_mutex> lock(write);
        // DO WRITE
    }
    
    // Multiple reads, no write
    void read_fun()
    {
        std::shared_lock<std::shared_mutex> lock(write);
        // do read
    }
    

    如果您不想使用 boost @howardhinmant,请提供指向 reference implementation 的链接

    【讨论】:

    • lock_guardshared_lock 上的互斥锁类型错误(应该是 std::shared_mutex)。这里还有一个参考实现:open-std.org/jtc1/sc22/wg21/docs/papers/2007/…
    • @HowardHinnant 已修复,伙计,我今天必须摆脱它,把一切都搞砸了,我也会将参考实现添加到答案中
    • +1 感谢您的出色回答。好吧,我想这就是我不能延长向我的项目添加这种巨大依赖的时间点。
    • @VSZM 你看到底部的参考实现的链接了吗,我觉得没那么大(你不需要添加 boost)
    • 恐怕 std::shared_mutex 在 c++17 中是(将是),而不是 c++14。
    【解决方案2】:

    这是安全的,但仍然可能不公平或不高效:

    std::atomic<int> readers;
    std::mutex write;
    
    // One write, no reads.
    void write_fun()
    {
        write.lock();// We lock the resource
        while(readers > 0){}// We wait till everyone finishes read.
        // DO WRITE
        write.unlock();// Release
    }
    
    // Multiple reads, no write
    void read_fun()
    {
        // We wait if it is being written.
        write.lock();
        readers++;
        write.unlock();
    
        // do read
        readers--;
    }
    

    使用条件变量的解决方案可以避免忙于等待readers 降至 0,留给读者作为练习。

    【讨论】:

    • 我相信这个算法很容易出现 writer starvation。如果读者经常回来,作者永远不会看到readers 降为零。我见过的最好的算法是由 Alexander Terekhov 设计的 2 门系统,并在此实现中使用:open-std.org/jtc1/sc22/wg21/docs/papers/2007/… 它禁止读取器和写入器饥饿。
    • @HowardHinnant 我不会将其作为一个强大的通用解决方案进行辩护,其目的是进行尽可能小的更改,为 OP 的方法提供安全性。但是,写入器饥饿不是问题 - 一旦写入器锁定互斥体,新读取器就无法访问。
    • +1 谢谢,现在我看到了我的代码中的错误。我也非常喜欢这个答案。太糟糕了,我只能选择一个。
    猜你喜欢
    • 2016-12-27
    • 2023-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-03
    相关资源
    最近更新 更多