让我们考虑这段代码(不一定有意义,它只是一个MCVE):

class Foo
{
public:
    // this function is thread safe
    void doSomething();
};

static std::mutex mutex;
static std::shared_ptr<Foo> instance;

void workerThread()
{
    while ( true )
    {
        mutex.lock();
        if ( instance )
        {
            instance->doSomething();
        }
        mutex.unlock();
        msleep( 50 );
    }
}

void messupThread()
{
    while ( true )
    {
        mutex.lock();
        instance.reset( new Foo() );
        mutex.unlock();
        msleep( 1000 );
    }
}
workerThreadFoo实例执行操作。 messupThread修改应在其上执行操作的实例。

此代码是线程安全的。

如果启动10个workerThread,问题就来了,当一个workerThread使用该实例时,它将锁定其他九个实例(而doSomething是线程安全的,它们应该可以同时工作)。

是否存在一种弱互斥/锁定机制,该机制会使任何workerThread阻止messupThread更改实例,但不会阻止并发workerThread使用它。

我可以这样做,但是我想知道是否存在使用标准对象/机制实现该目标的简便方法:
class Foo
{
public:
    // this function is thread safe
    void doSomething();
};

static int useRefCount = 0;
static std::mutex work_mutex; // to protect useRefCount concurrent access
static std::mutex mutex;      // to protect instance concurrent access
static std::shared_ptr<Foo> instance;

void workerThread()
{
    while ( true )
    {
        work_mutex.lock();
        if ( useRefCount == 0 )
            mutex.lock(); // first one to start working, prevent messupThread() to change instance
        // else, another workerThread already locked the mutex
        useRefCount++;
        work_mutex.unlock();

        if ( instance )
        {
            instance->doSomething();
        }

        work_mutex.lock();
        useRefCount--;
        if ( useRefCount == 0 )
            mutex.unlock(); // no more workerThread working
        //else, keep mutex locked as another workerThread is still working
        work_mutex.unlock();

        msleep( 50 );
    }
}

void messupThread()
{
    while ( true )
    {
        mutex.lock();
        instance.reset( new Foo() );
        mutex.unlock();
        msleep( 1000 );
    }
}

最佳答案

如果您可以访问 std::shared_mutex ,则可以很好地解决您的问题。它基本上是一个读/写锁,但具有不同的命名法:共享访问与唯一访问。

让工作线程使用shared lock,让消息线程使用unique lock

首选共享访问还是唯一访问,depends on the implementation。因此,由于大量工作线程非常频繁地使用共享锁,因此您可能会看到Messup线程处于饥饿状态。

// Worker thread:
std::shared_lock<std::shared_mutex> lock(m_mutex);

// Messup thread:
std::unique_lock<std::shared_mutex> lock(m_mutex);

注意std::shared_mutex是C++ 17标准的一部分。

关于c++ - 是否存在某种弱互斥概念?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46602842/

10-09 21:03