如何正确序列化线程访问控制循环的标志
How to correctly serialise thread access to a flag controlling a loop
我有一个函数 f1,它包含一个简单的循环,它通过布尔标志进行控制。该标志未写入 f1 内部。
我还有一个清除标志的函数。
这两个函数是在不同的线程上调用的。
如果我在 f1 进入循环之前锁定互斥量,那么 f2 将无法获取它以清除标志。
如果我在进入 f1 中的循环之前不锁定互斥体,则该标志不受保护。考虑到函数只读取它,这有关系吗?
我的问题是我是否需要在进入 f1 循环之前保护标志,因为它只被读取?如果是这样,如何?
如果标志只写入一个地方,我还需要互斥体吗?
我是否遗漏了一些基本的东西?
TIA
class X
{
public:
X() :
m_thread(),
m_isDone(false),
m_mutex()
{
m_thread = std::unique_ptr<std::thread>(new std::thread( [=]{ run(); } ));
}
~X()
{
// tell the thread to exit
m_isDone = true;
// wait for the thread to terminate
m_thread->join();
}
void f1()
{
// locking the mutex will prevent f2 from clearing the flag
std::lock_guard<std::mutex> lock(m_mutex);
while (!m_isDone)
{
// do some stuff
}
}
void f2()
{
// lock the mutex
std::lock_guard<std::mutex> lock(m_mutex);
m_isDone = true;
}
private:
std::unique_ptr<std::thread> m_thread;
bool m_isDone;
mutable std::mutex m_mutex;
};
只需更改:
bool m_isDone;
至:
std::atomic<bool> m_isDone;
这将使您对 m_isDone
的读写保证原子性(您需要这样做,因为它是在不同的线程中读写的)。 atomic
也消除了对任何类型的互斥锁、锁等的需要。
请注意,在您的解决方案中,f1
持有锁 永远 ,因此 f2
永远无法获得它。带锁的正确解决方案是更复杂和不必要的:
bool isDone() { // easily replaced by atomic load
std::lock_guard<std::mutex> lock(m_mutex);
return m_isDone;
}
void f1() {
while (!isDone()) {
// stuff
}
}
我有一个函数 f1,它包含一个简单的循环,它通过布尔标志进行控制。该标志未写入 f1 内部。
我还有一个清除标志的函数。
这两个函数是在不同的线程上调用的。
如果我在 f1 进入循环之前锁定互斥量,那么 f2 将无法获取它以清除标志。
如果我在进入 f1 中的循环之前不锁定互斥体,则该标志不受保护。考虑到函数只读取它,这有关系吗?
我的问题是我是否需要在进入 f1 循环之前保护标志,因为它只被读取?如果是这样,如何?
如果标志只写入一个地方,我还需要互斥体吗?
我是否遗漏了一些基本的东西?
TIA
class X
{
public:
X() :
m_thread(),
m_isDone(false),
m_mutex()
{
m_thread = std::unique_ptr<std::thread>(new std::thread( [=]{ run(); } ));
}
~X()
{
// tell the thread to exit
m_isDone = true;
// wait for the thread to terminate
m_thread->join();
}
void f1()
{
// locking the mutex will prevent f2 from clearing the flag
std::lock_guard<std::mutex> lock(m_mutex);
while (!m_isDone)
{
// do some stuff
}
}
void f2()
{
// lock the mutex
std::lock_guard<std::mutex> lock(m_mutex);
m_isDone = true;
}
private:
std::unique_ptr<std::thread> m_thread;
bool m_isDone;
mutable std::mutex m_mutex;
};
只需更改:
bool m_isDone;
至:
std::atomic<bool> m_isDone;
这将使您对 m_isDone
的读写保证原子性(您需要这样做,因为它是在不同的线程中读写的)。 atomic
也消除了对任何类型的互斥锁、锁等的需要。
请注意,在您的解决方案中,f1
持有锁 永远 ,因此 f2
永远无法获得它。带锁的正确解决方案是更复杂和不必要的:
bool isDone() { // easily replaced by atomic load
std::lock_guard<std::mutex> lock(m_mutex);
return m_isDone;
}
void f1() {
while (!isDone()) {
// stuff
}
}