我需要创建一个函数,该函数将值附加到向量并返回刚刚附加的值的索引。
示例:
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
返回刚添加的项目的索引,那将很容易。如何保证返回正确的索引?
答案 0 :(得分:11)
std::vector
没有内置线程支持。您可以使用boost::mutex
来扩展它:
int append(std::vector<int>& numbers, int number){
boost::mutex::scoped_lock slock( my_lock );
int retval = numbers.size();
numbers.push_back(number);
return retval;
}
您需要以这种方式保护任何读/写操作。另一种方法是为std::vector
创建包装类,它将通过线程支持扩展它。有关详细信息,请查看this问题。
答案 1 :(得分:3)
STL容器不是线程安全的(即使只调用push_back()
),你必须自己解决这个问题 - 在STL之外使用一些合适的同步原语。
答案 2 :(得分:2)
在Visual Studio 2010中,您可以使用concurrent_vector,它提供同步增长功能。 This topic列出了每个并发容器。
请注意,英特尔TBB中也提供了相同的语法+语义,因此可以跨平台使用。
答案 3 :(得分:0)
您需要使用互斥锁来保证返回正确的索引
答案 4 :(得分:0)
最强保证的解决方案是将整个矢量锁定在所有此类操作上(这意味着从代码中的任何位置控制每个操作,这实际上意味着创建同步矢量)。
这可能是一件如此简单的事情可以用于您的目的:
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);
int newSize = numbers.size();
//this bit is as a short-cut in common, easy, cases
if(newSize = retval + 1) //no need for further complication
return retval;
while(++retval < newSize)
if(numbers[retval] == number)
return retval;
//If we get this far, numbers have been deleted, not added. More discussion below.
}
关于这一点的一点是,如果线程按3,3,3,3,那么返回的索引将是错误的,但它仍然是3的索引。是否可以取决于你的目的。
另一个是如果在此期间弹出或以其他方式缩短向量,那么我们最多只能在上面的代码中添加注释,更糟糕的是错误(因为它们在我们获得newSize后再次弹出) ,然后访问[retval]变为无效)。你需要考虑这种情况是否会发生(也许你从其他代码中知道它永远不会发生)以及如果它会怎么做。
如果这个限制对你的用例来说太大了,那么生成一个完全同步的向量是我能想到的最好的恐惧。