[英]Thread-safe and unique execution of nested function
I have a class MyClass
whose function A
is executed many times in parallel. 我有一个MyClass
类,其函数A
并行执行多次。 Then, there is function B
that should only be executed once. 然后,有一个功能B
只能执行一次。 My initial setup looks simple but I doubt that it is thread-safe. 我的初始设置看起来很简单,但是我怀疑它是线程安全的。 How can I make it thread-safe? 如何使其成为线程安全的? I'm using C++11. 我正在使用C ++ 11。
class MyClass {
public:
void A() {
static bool execute_B = true;
if (execute_B) {
execute_B = false;
B();
}
}
private:
void B() {
std::cout << "only execute this once\n";
}
};
This is a primary use-case for std::atomic_flag
: 这是std::atomic_flag
的主要用例:
class MyClass {
public:
void A() {
if (!execute_B_.test_and_set()) {
B();
}
}
private:
void B() {
std::cout << "only execute this once\n";
}
std::atomic_flag execute_B_ = ATOMIC_FLAG_INIT;
};
Note that any solutions involving static
will allow only one invocation of MyClass::B
, even across multiple MyClass
instances, which may or may not make sense for you; 请注意,任何涉及static
解决方案都只允许一次MyClass::B
调用,即使在多个MyClass
实例之间也是如此,这可能对您没有意义; assuming it doesn't make sense, this approach instead allows one invocation of MyClass::B
per MyClass
instance. 假设这没有意义,则此方法允许每个 MyClass
实例一次调用MyClass::B
Yes, your code is not thead-safe: several threads can enter inside the body of if
statement before execute_B
will be set to false. 是的,您的代码不是安全的:多个线程可以在execute_B
设置为false之前的if
语句内输入。 Also, execute_B
is not atomic, so you can have problems with visibility of changes between threads. 另外, execute_B
也不是原子的,因此线程之间更改的可见性可能会有问题。
There are many ways you can make it thread-safe. 有很多方法可以使其成为线程安全的。 Note that version (1), (2) and (4) will block other thread from executing A
past the point of B
execution, until B
execution is finished. 请注意,版本(1),(2)和(4)将阻止其他线程在B
执行点之后执行A
,直到B
执行完成。
1) Already mentioned std::call_once
: 1)已经提到过std::call_once
:
void A() {
static std::once_flag execute_B;
std::call_once(flag1, [this](){ B(); });
}
2) Calling B
as result of initializating static variable: 2)调用B
作为初始化静态变量的结果:
void A() {
static bool dummy = [this](){ B(); return true; });
}
3) Using atomic exchange: 3)使用原子交换:
void A() {
static std::atomic<bool> execute_B = true;
if(execute_B.exchange(false, std::memory_order_acq_rel))
B();
}
4) Protecting check with a mutex (to avoid perfomance degradation later, use double-checked locking): 4)用互斥锁保护检查(为避免以后性能下降,请使用双重检查锁定):
void A() {
static std::mutex m_;
static std::atomic<bool> execute_B = true;
if(execute_B.load(std::memory_order_acquire)) {
std::unique_lock<std::mutex> lk(m_);
if(execute_B.load(std::memory_order_relaxed)) {
B();
execute_B.store(false, std::memory_order_release);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.