让我们考虑这段代码(不一定有意义,它只是一个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 );
}
}
workerThread
对Foo
实例执行操作。 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/