首页 > 解决方案 > 防止对类成员的并发读/写

问题描述

搜索但找不到清晰,所以这是我的问题:
需要更新和读取来自不同线程的成员,如下所示:

template<typename T> struct State
{
    std::map<std::string, T> statedata;
    static std::mutex mux_state;
    ...
    void update(std::string k, T t)
    {
        while (!mux_state.try_lock()) timeoutdelay(TOD_UPDATE);
        ..do update..
        mux_state.unlock();
    }
    ...
    T read(std::string k)
    {
        while (!mux_state.try_lock()) timeoutdelay(TOD_READ);
        T t=statedata[k];
        mux_state.unlock();
        return t;
    }
    ...
}
...
State<mytype> state;
...
..from thread_1() randomly
    state.update(..)
...
..from thread_2() randomly
    state.read(..)

需要 update() 和 read() 调用始终具有独占访问权限。我上面的方案是否可以实现这一点,或者有更好/正确的方法吗?

timeoutdelay()隐藏中止条件,以便调用线程不会被无限期阻塞。

标签: c++multithreading

解决方案


用 替换while循环std::lock_guard。这样的繁忙循环会阻塞调用线程,直到获得锁,所以让守卫为你做阻塞。不要std::mutex手动锁定/解锁,让守卫来做:

template<typename T>
struct State
{
private:
    std::map<std::string, T> statedata;
    std::mutex mux_state;

public:
    ...
    void update(std::string k, T t)
    {
        std::lock_guard<std::mutex> g(mux_state);
        statedata[k] = std::move(t);
    }
    ...
    T read(std::string k)
    {
        std::lock_guard<std::mutex> g(mux_state);
        return statedata[k];
    }
    ...
};

更新:如果您在等待获得互斥锁时确实需要超时,以便您可以做其他事情,您可以使用std::timed_mutex

template<typename T>
struct State
{
private:
    std::map<std::string, T> statedata;
    std::timed_mutex mux_state;

public:
    ...
    bool update(std::string k, T t)
    {
        while (!mux_state.try_wait_for(std::chrono::milliseconds(TOD_UPDATE))) {
            if (check_abort_conditions())
                return false;
        }
        statedata[k] = std::move(t);
        return true;
    }
    ...
    bool read(std::string k, T &value)
    {
        while (!mux_state.try_wait_for(std::chrono::milliseconds(TOD_UPDATE))) {
            if (check_abort_conditions())
                return false;
        }
        value = statedata[k];
        return true;
    }
    ...
};

使用std::mutex::try_lock()(或std::timed_mutex::try_lock())立即返回,这可能不允许调用线程在繁忙循环中使用时让给其他线程。Usingstd::timed_mutex::try_wait_for()使调用线程进入休眠状态,直到超时结束,从而允许其他线程运行。


推荐阅读