如何正确地序列化对控制循环的标志的线程访问

时间:2015-01-29 17:32:33

标签: c++ multithreading c++11 locking mutex

我有一个函数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;
};

1 个答案:

答案 0 :(得分:1)

只需改变:

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
    }
}