如何在不饥饿的情况下锁定 std::mutex

问题描述 投票:0回答:3

在我的程序中,我有一个互斥锁和两个线程。这些线程之一经常获取锁。另一个线程尝试获取但必须永远等待。

是否会因为释放锁后获取锁的速度太快而导致其他线程没有机会?互斥体总是给每个人一个机会吗?如果没有,什么是好的解决方案?(某种 FIFO 锁?)

我正在使用

std::mutex
std::lock_guard

问题扩展 seccpur 指出,

std::condition_variable
将是解决此问题的方法。这如何通过三个线程进行扩展?
std::condition_variable
是否确保每个线程都能转动?假设您使用
notify_one()

c++ locking mutex starvation
3个回答
4
投票

std::mutex 并不能保证给每个人平等的机会。因此,一个线程可能会导致另一个线程挨饿。您可以尝试的第一件事是插入 std::this_thread::yield() 并查看是否有帮助。如果这没有帮助,那么您的代码一定存在逻辑错误。发布部分代码,我们可以帮助您进一步诊断。


3
投票

使用 seccpur 的提示,我想出了以下解决方案来防止单个线程挨饿。

#include <condition_variable>
#include <mutex>
#include <atomic>

class NoStarveLock
{
    std::condition_variable condition;
    std::atomic_flag flag = ATOMIC_FLAG_INIT;
    std::mutex conditionLock;
public:
    void lock()
    {
        std::unique_lock<std::mutex> lck(conditionLock);
        while (flag.test_and_set()) // multiple threads can wake up at the same time, so use a set+test
        {
            condition.wait(lck); // wait for a wakeup
        }
    }

    void unlock()
    {
        std::unique_lock<std::mutex> lck(conditionLock);
        flag.clear();
        condition.notify_all();
    }
};

0
投票

使用

std::mutex
std::lock_guard
std::unique_lock
(阅读器)和
std::condition_variable
的示例。 _mutexLockCondition、_mutexObject 和 _dataContainer 在 ReaderClass 和 WriterClass 之间共享。

试图对实际数据容器有点模糊,所以

getDataContainer()
addDataToContainer()
取决于你。

std::shared_ptr< Data > ReaderClass::read()
{
    std::unique_lock< std::mutex > lock( _mutexObject );

    // handle spurious wakeup from waitForMessageNotification
    while( _dataContainer.empty() )
    {
        if( waitForMessageNotification( lock ) )
        {
            // timeout occurred, return nullptr to prevent blocking
            return nullptr;
        }
    }

    return getDataFromContainer();
}

bool ReaderClass::waitForNotification( unique_lock< mutex > & lock )
{
    //_mutexLockCondition is a std::condition_variable
    return _mutexLockCondition.wait_for( lock, std::chrono::milliseconds( 100 ) )
                                            == std::cv_status::timeout;
}


void WriterClass::write( std::shared_ptr< Data > dataPtr )
{
    std::lock_guard< mutex > lock( _mutexObject );

    addDataToContainer( dataPtr );

    _mutexLockCondition.notify_one();
}
© www.soinside.com 2019 - 2024. All rights reserved.