我是否需要在返回容器副本的函数上添加锁?

Avi*_*ano 3 c++ multithreading

class Manager {
public:

    list<Employee> getEmployees() {
        // Do I need to lock here?
        return emps_;
    }
    void addEmp(Employee emp); //Here I have lock
private:
    list<Employee> emps_;
};
Run Code Online (Sandbox Code Playgroud)

实例Manager在多个线程之间共享.我是否需要为getEmployees成员函数添加锁定?

我很确定我需要一个锁,因为复制了完整的列表,所以在此期间进行的任何修改(直到复制完成)都可能会破坏复制操作.

我只是问这个,因为我很少有人认为没有必要锁定.

编辑:

由于现在需要锁定,我的问题是如何以最小的开销来做到这一点.通过以下解决方案,您可以将列表复制两次:

list<Employee> getEmployees() {
    pthread_mutex_lock( &mutex1 );
    list<Emp> tmp  = emps_; //Copy 1 
    pthread_mutex_unlock( &mutex1 );
    return tmp;//Copy 2
}
Run Code Online (Sandbox Code Playgroud)

Who*_*aig 12

复制整个列表,但副本的来源可能正在修改中.stdlib容器支持完全并发的解锁读取访问.写的另一方面......

如果您在创建副本时要写入此列表,则需要将其锁定.一个SWMR(Single Writer Multi Reader)锁是理想的,顺便说一下,特别是如果你有几十个甚至几百个需要复制的线程,只需偶尔写一次.即使这样,编写器请求的缺乏也是一个真正关心的问题,需要通过锁定类的实现来解决,但不是这里的问题范围(没有双关语意).

关于你的更新,在适当的时候,我是范围释放锁的忠实粉丝,在你的情况下它们也是如此.即你的互斥体周围的范围对象包装器,它在入口处锁定它,并在范围 - 退出时将其解锁.

我很确定boost :: guys有这样的东西很容易访问,并且就此而言C++ 11也可能(由于工作时间表我没有采取过那种暴跌;没有停机时间呃).但你想要这样的东西:

list<Employee> getEmployees() 
{
    scope_lock latch(&mtx);
    return emps_;
}
Run Code Online (Sandbox Code Playgroud)

scope_lock上面只是一个简单的类锁存建设互斥,并解锁它破坏.这可以防止复制构造中抛出的异常不会永久挂起您的互斥锁的真实可能性.可以将其视为利用自动销毁来解锁互斥锁.RAII获胜.

我希望这是有道理的.对于像这样的小型玩家来说,这样的事情是理想的.同样,包括boost在内的许多工具包很可能会内置这样的东西,如果有任何提升家伙读到这个,请牛仔起来并借给指针.上面的例子就像你可以获得的范围锁定一样简单.

最后,对于SWMR,逻辑完全相同.唯一的区别是锁会对你是否要求读或写访问进行额外的论证.

  • @ user1495181本地变量的析构函数被称为_after_已复制出任何返回值. (2认同)