我有一个关于线程安全和互斥的问题。我有两个可能无法同时执行的函数,因为这可能会导致问题:
std::mutex mutex;
void A() {
std::lock_guard<std::mutex> lock(mutex);
//do something (should't be done while function B is executing)
}
T B() {
std::lock_guard<std::mutex> lock(mutex);
//do something (should't be done while function A is executing)
return something;
}
现在的问题是,功能A和B不应该同时执行。这就是我使用互斥锁的原因。但是,如果从多个线程同时调用函数B,则完全没问题。但是,互斥锁也可以防止这种情况(我不想这样做)。现在,有没有办法确保A和B不会同时执行,同时仍然让函数B并行执行多次?
答案 0 :(得分:3)
如果选择C ++ 14,则可以使用共享互斥锁(有时称为“读写器”互斥锁)。基本上,在函数A()
内部,您将获得一个唯一的(独占的“编写器”)锁,而在函数B()
内,您将获得一个共享(非独占的“读者”)锁。
只要存在共享锁,就不能通过其他线程 获取互斥锁(但可以非排他地获取);只要存在独占锁,无论如何都不能通过任何其他线程获取互斥锁。
结果是您可以让多个线程同时执行函数B()
,而函数A()
的执行可以防止其他线程同时执行A()
和B()
:
#include <shared_mutex>
std::shared_timed_mutex mutex;
void A() {
std::unique_lock<std::shared_timed_mutex> lock(mutex);
//do something (should't be done while function B is executing)
}
T B() {
std::shared_lock<std::shared_timed_mutex> lock(mutex);
//do something (should't be done while function A is executing)
return something;
}
请注意,即使对于B()
的并发执行,也会始终存在一些同步开销,并且这是否最终会比使用普通互斥锁提供更好的性能,这在很大程度上取决于这些函数内部和外部的内容 - 在提交更复杂的解决方案之前始终进行测量。
Boost.Thread还提供了shared_mutex
。
答案 1 :(得分:0)
你可以选择C ++ 14
使用std::shared_timed_mutex
。
A
会使用lock
,B
会使用lock_shared
答案 2 :(得分:0)
这很可能充满了bug,但由于你没有C ++ 14,你可以围绕std::mutex
创建一个锁定计数包装器并使用它:
// Lock-counting class
class SharedLock
{
public:
SharedLock(std::mutex& m) : count(0), shared(m) {}
friend class Lock;
// RAII lock
class Lock
{
public:
Lock(SharedLock& l) : lock(l) { lock.lock(); }
~Lock() { lock.unlock(); }
private:
SharedLock& lock;
};
private:
void lock()
{
std::lock_guard<std::mutex> guard(internal);
if (count == 0)
{
shared.lock();
}
++count;
}
void unlock()
{
std::lock_guard<std::mutex> guard(internal);
--count;
if (count == 0)
{
shared.unlock();
}
}
int count;
std::mutex& shared;
std::mutex internal;
};
std::mutex shared_mutex;
void A()
{
std::lock_guard<std::mutex> lock(shared_mutex);
// ...
}
void B()
{
static SharedLock shared_lock(shared_mutex);
SharedLock::Lock mylock(shared_lock);
// ...
}
...当然,除非你想潜入Boost。