有一种弱互斥概念吗?
Is there a sort fo weak mutex concept?
让我们考虑一下这段代码(不一定有意义,它只是一个 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 );
}
}
A workerThread
对 Foo
实例进行操作。 A messupThread
修改应在其上执行操作的实例。
这段代码是线程安全的。
如果启动 10 workerThread
就会出现问题,当一个 workerThread
使用该实例时,它将锁定其他九个(而 doSomething
是线程安全的,它们应该能够同时工作)。
是否有一种弱 mutex/lock 机制可以使任何 workerThread
阻止 messupThread
更改实例但不会阻止并发 workerThread
使用它.
我可以这样做,但我想知道是否有更简单的方法来使用标准 objects/mechanisms:
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 );
}
}
如果所有线程都应该共享同一个智能指针 instance
,那么一开始就使用 std::shared_ptr
没有多大意义,而是 std::unique_ptr
。
我是否可以建议每个线程都有自己的 std::shared_ptr
,从全局 instance
共享指针复制?然后,在锁的保护下,你从全局共享指针复制到本地共享指针,当锁被解锁时,你通过本地共享指针调用doSomething
函数。
可能是
void workerThread()
{
std::shared_ptr<Foo> local_instance;
while (true)
{
{
std::scoped_lock lock(mutex);
local_instance = instance;
}
if (local_instance)
{
local_instance->doSomething();
}
msleep(50);
}
}
如果您可以访问 std::shared_mutex
,它可能会很好地解决您的问题。它基本上是一个 read/write 锁,但具有不同的命名法:共享访问与唯一访问。
让工作线程占用shared lock, and let the messup thread take a unique lock。
共享访问还是独有访问是首选,。所以你可能会看到你的混乱线程因为大量的工作线程非常频繁地获取共享锁而饿死。
// 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 标准的一部分。
让我们考虑一下这段代码(不一定有意义,它只是一个 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 );
}
}
A workerThread
对 Foo
实例进行操作。 A messupThread
修改应在其上执行操作的实例。
这段代码是线程安全的。
如果启动 10 workerThread
就会出现问题,当一个 workerThread
使用该实例时,它将锁定其他九个(而 doSomething
是线程安全的,它们应该能够同时工作)。
是否有一种弱 mutex/lock 机制可以使任何 workerThread
阻止 messupThread
更改实例但不会阻止并发 workerThread
使用它.
我可以这样做,但我想知道是否有更简单的方法来使用标准 objects/mechanisms:
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 );
}
}
如果所有线程都应该共享同一个智能指针 instance
,那么一开始就使用 std::shared_ptr
没有多大意义,而是 std::unique_ptr
。
我是否可以建议每个线程都有自己的 std::shared_ptr
,从全局 instance
共享指针复制?然后,在锁的保护下,你从全局共享指针复制到本地共享指针,当锁被解锁时,你通过本地共享指针调用doSomething
函数。
可能是
void workerThread()
{
std::shared_ptr<Foo> local_instance;
while (true)
{
{
std::scoped_lock lock(mutex);
local_instance = instance;
}
if (local_instance)
{
local_instance->doSomething();
}
msleep(50);
}
}
如果您可以访问 std::shared_mutex
,它可能会很好地解决您的问题。它基本上是一个 read/write 锁,但具有不同的命名法:共享访问与唯一访问。
让工作线程占用shared lock, and let the messup thread take a unique lock。
共享访问还是独有访问是首选,
// 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 标准的一部分。