如果我们同时从向量中追加和读取数据,我们是不是需要锁定?(无修改)
Posted
技术标签:
【中文标题】如果我们同时从向量中追加和读取数据,我们是不是需要锁定?(无修改)【英文标题】:Do we need locking if we are appending and reading data from vector simultaneously?(no-modification)如果我们同时从向量中追加和读取数据,我们是否需要锁定?(无修改) 【发布时间】:2021-05-06 17:28:45 【问题描述】:我们知道,如果多个线程对一个对象进行操作并且涉及到修改,我们需要某种锁定(原子/互斥锁)。就我而言,只有这些操作同时发生在 std::vector 上:
1. Read
2. Append/Push
在这种情况下,向量是否需要锁?如果是,为什么?我的程序是基于 CPP 的。
我是锁概念的新手。任何正确方向的提示都对我有用。
【问题讨论】:
追加时,可能需要重新分配。 追加 (push_back) 时,您需要完全锁定阻塞读取、写入和追加,因为向量的内部存储可能会被重新分配。如果您可以预先分配向量并且不在线程之间共享数组元素,则不需要锁定。 【参考方案1】:是的,您通常需要锁定,因为push_back
会导致重新分配。
您可以查看参考:
https://en.cppreference.com/w/cpp/container/vector/push_back 说
如果新的 size() 大于 capacity() 则所有迭代器和 引用(包括过去的迭代器)无效。 否则只有过去的迭代器无效。
https://www.cplusplus.com/reference/vector/vector/push_back/ 提及:
容器已修改。如果发生重新分配,所有包含 元素被修改。否则,不会访问现有元素,并且 同时访问或修改它们是安全的。
所以,如果你想小心的话,你应该锁定。或者,如果您关心干净的可维护代码。
如果您需要额外的性能并且知道自己在做什么,那么只有当您知道没有push_back()
会使size()
高于capacity()
时,您才能摆脱锁定。这是非常棘手且容易出错的:一旦您允许一个线程开始读取,您必须确保在其他线程中不会发生重新分配,甚至更晚。
编辑:上面重新措辞。 tl-dr:使用同步 :-)
【讨论】:
只有在否时,你才能摆脱锁定,因为当写入线程锁定并重新分配时,一个(或多个)线程可能处于读取访问中间(即,读线程在写入器获取时已经超过锁)。你可以试着花点心思让作者等到没有活跃的读者,但即便如此,也有一些微妙的问题需要考虑。 @1201ProgramAlarm 在高性能系统上,可以使用信号量,允许多个并发读取器,并在 push_back 重新分配之前强制读取器退出。但是,是的,可能比 OP 需要的更先进。 (感谢您指出原始答案中的错误)【参考方案2】:您很可能需要资源锁定。举这个例子,如果你在向量中插入一个元素,它可能会调整大小。现在,当您调整向量的大小时,如果另一个线程尝试访问数组中的数据怎么办。看到冲突了吗?这就是为什么需要锁定资源。现在这是您插入或删除数据的情况(这意味着您更改了容器的实际分配)。如果大小是固定的(也就是说,如果您已经预先分配了它),那么就不会有问题。
【讨论】:
以上是关于如果我们同时从向量中追加和读取数据,我们是不是需要锁定?(无修改)的主要内容,如果未能解决你的问题,请参考以下文章