原子 std::vector::push_back() 和返回索引
我需要创建一个函数,它将一个值附加到一个向量并返回刚刚附加的值的索引。
示例:
int append(std::vector<int>& numbers, int number){
int retval = numbers.size();
// what if some other thread calls push_back(number) in between these calls?
numbers.push_back(number);
return retval;
}
我想以原子方式执行此操作,以便即使可能有多个线程向向量附加值,返回的索引也始终正确。如果 push_back
返回刚刚添加的项目的索引,那就很容易了。如何保证返回正确的索引?
I need to create a function which appends a value to a vector and returns the index of the value that was just appended.
Example:
int append(std::vector<int>& numbers, int number){
int retval = numbers.size();
// what if some other thread calls push_back(number) in between these calls?
numbers.push_back(number);
return retval;
}
I would like to do this atomically so that the returned index is always correct even when there may be multiple threads appending values to the vector. It would have been easy if push_back
returned the index of the item just added. How can I guarantee that the correct index is returned?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
std::vector
没有内置线程支持。您可以使用 boost::mutex 来扩展它:您需要以这种方式保护任何读/写操作。另一种方法是为
std::vector
创建包装类,以通过线程支持来扩展它。有关详细信息,请查看此问题。std::vector
has no built in thread support. You could useboost::mutex
to extend it:You need to protect any read/write operation in such way. Another way is to create wrapper class for
std::vector
that will extend it with thread support. Check this question for details.STL 容器不是线程安全的(即使是单独调用
push_back()
),您必须自己解决这个问题 - 在 STL 之外使用一些合适的同步原语。STL containers are not thread-safe (even the call to
push_back()
alone), you'll have to solve this problem on your own - use some suitable synchronization primitives outside STL.在 Visual Studio 2010 中,您可以使用 concurrent_vector 来实现此目的,它提供同步增长功能。 本主题列出了每个并发容器。
请注意,这些在英特尔的 TBB 中也可用,具有相同的语法 + 语义,因此可以跨平台使用。
In Visual Studio 2010, you can use a concurrent_vector for this in , it offers synchronized grow functionality . This topic lists each of the concurrent containers.
Note that these are also available in Intel's TBB with identical syntax + semantics and as such are available cross platform.
您需要使用互斥体来保证返回正确的索引
You need to use a mutex to guarantee that the correct index is returned
最有力的保证解决方案是在所有此类操作上锁定整个向量(这意味着从代码中的任何位置控制每个操作,这实际上意味着创建一个同步向量)。
也许像这样简单的事情就可以满足您的目的:
关于这一点的一件事是,如果线程推送 3, 3, 3, 3,那么返回的索引将是错误的,尽管它仍然是 3 的索引。这是否可以取决于您的目的。
另一个是,如果向量同时被弹出或以其他方式缩短,那么最好的情况是我们只是在上面的代码中添加注释,最糟糕的是它会出错(因为它们在我们获得 newSize 后再次弹出,然后访问[retval]无效)。您需要考虑这种情况是否会发生(也许您从代码的其余部分知道它永远不会发生)以及如果发生了该怎么办。
如果这种限制对于您的用例来说太大,那么恐怕生成完全同步的向量是我能想到的最好的。
The strongest-guarantee solution is to lock the entire vector on all such operations (which means controlling every operation from everywhere in the code, which really means creating a synchronised vector).
It may be that something as simple as this will do for your purposes:
One thing about this is that if threads push 3, 3, 3, 3 then the index returned will be wrong, though it will still be an index to a 3. Whether that's okay or not depends on your purposes.
Another is that if the vector is popped or otherwise shortened in the meantime, then at best we get to the point where I just put a comment in the code above, at worse it errors (as they pop again after we obtain newSize, and then accessing [retval] becomes invalid). You need to consider if this case can happen (maybe you know from the rest of the code that it never will) and what to do if it does.
If the limitations of this are too great for your use case, then producing a fully synchronised vector is the best I can think of I'm afraid.
如果您知道所需的最大大小并使用原子计数器来增加当前元素索引,则可以使用自己的容器在没有互斥锁的情况下执行此操作,例如:
You can do this without Mutex with your own container if you can know the maximum required size and use an atomic counter to increment the current element index, e.g. :