在这种情况下,我应该使用lock_guard、scoped_lock还是unique_lock?

6

我已经阅读了许多关于这个问题的答案,但是没有一个给我清晰地理解当我有多个写入者但只有一个读取者时该使用哪个。下面的代码是我所说的一个人为的例子。

struct StateInfo {
    long wd{};
    uint32_t perc{};
};

class Blah 
{
    const int numDevices = getDevices();
    std::shared_mutex sharedMutexSI_;
    vector<StateInfo> stateInfo;
public:

    Blah() : stateInfo(numDevices){};

    void writers(StateInfo &newSi, const int i)
    {
        std::shared_lock<std::shared_mutex> _MULTIPLE(sharedMutexSI_);
        stateInfo[i] = newSi;
    }

    StateInfo reader(const int i)
    {
        std::lock_guard<std::shared_mutex> _EXCLUSIVE(sharedMutexSI_);
        return stateInfo[i];
    }
};

现在的情况是多个编写者可能同时更新stateInfo向量,但它们不会更新向量中相同的项,因为i 是每个线程唯一的。一个单独的读取线程可以随时尝试读取任意的向量项。

  1. 以上代码是否正确避免了竞争条件?

  2. lock_guard 是否是合适的锁定方式,还是应该使用 scoped_lockunique_lock


我的理解是,如果我不需要scoped_lock的功能,那么lock_guard是最简单的选择,我应该坚持使用最简单的方法? - poby
1
至少在libstdc++中,对于单个互斥锁,lock_guardscoped_lock在其实现上是相同的。 - Evg
1
关于 lock_guardscoped_lockunique_lock:请参见此处的专门问题和答案(https://dev59.com/bFgQ5IYBdhLWcg3wRR5j)。 - anatolyg
1
@ALX23z,OP有一个读者和几个写者,并且写者之间没有数据竞争。 - Evg
1
@Evg 你的意思是他有为每个索引专门负责的编写者吗?这是在类外做出的一种推测,通常情况下并不好。在这种情况下,最好让每个状态信息都有自己的 std::mutex 或者将 StateInfo 设为原子类型。无论如何,该类都存在虚假共享问题,因此我不确定共享锁是否有很大帮助。 - ALX23z
显示剩余8条评论
1个回答

2

总结一下之前的评论:

是的,这段代码是正确的。然而,它可能效率低下,因为它禁止在写入另一个数组元素时读取任何数组元素。你可能需要使用每个数组元素的mutex来进行更细粒度的同步。

class Blah 
{
    const int numDevices = getDevices();
    std::vector<std::mutex> mutexes;
    std::vector<StateInfo> stateInfo;
public:

    Blah() : mutexes(numDevices), stateInfo(numDevices){}

    void writers(StateInfo &newSi, const int i)
    {
        std::lock_guard<std::mutex> guard(mutexes[i]);
        stateInfo[i] = newSi;
    }

    StateInfo reader(const int i)
    {
        std::lock_guard<std::mutex> guard(mutexes[i]);
        return stateInfo[i];
    }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接