2010-08-10 95 views
5

我需要创建一个函数,它将一个值附加到一个向量并返回刚刚追加的值的索引。Atomically 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返回刚刚添加的项目的索引,将会很容易。我怎样才能保证返回正确的索引?

+5

实际上,如果push_back()返回一个索引并不容易,因为push_back()本身不是线程安全的 – 2010-08-10 09:20:31

+0

您需要保护容器免受所有并发写入的影响。并发普通push_back()已经需要向量外部同步 – 2010-08-10 09:20:57

+3

请记住,对于许多真实世界的应用程序来说,制作小型线程安全操作并不是正确的解决方案:您应该考虑保护更大的代码块。如果您将它们用作通信机制,则线程安全集合是很好的。也就是说,这可能是这种情况。 – 2010-08-10 10:57:43

回答

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

当另一个线程使用除了调用此函数之外的其他线程时,这是如何工作的?另一个调用numbers.clear()的线程不会在这里遵守scoped_lock。 – 2010-08-10 09:31:11

+0

这会起作用,但它只会保证这一次操作。任何人都可以在同一个对象的其他地方执行'push_back()'并将其破解。 – sharptooth 2010-08-10 09:31:52

+4

需要保护任何读/写操作。可能是OP应该为'std :: vector'创建包装类,它将使用线程支持来扩展它。有关详细信息,请查看[this](http://stackoverflow.com/questions/1099513/threadsafe-vector-class-for-c)问题。 – 2010-08-10 09:36:48

3

STL容器不是线程安全的(即使是单独调用push_back()),你必须自己解决这个问题 - 在STL之外使用一些合适的同步原语。

0

你需要使用一个互斥体,保证返回正确的指数

+0

这实在是一个评论,而不是对问题的回答。请使用“添加评论”为作者留下反馈。 – 2012-08-21 08:46:17

+2

不同意。我相信这是一个答案。接受的答案也给出了相同的建议,但有一个例子。 – 2012-08-21 08:53:26

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]变得无效)。你需要考虑这种情况是否会发生(也许你从其他代码中知道它永远不会发生)以及如果发生这种情况该怎么办。

如果这个限制对你的用例来说太大了,那么生成一个完全同步的矢量是我能想到的最好的恐惧。

2

在Visual Studio 2010中,您可以使用concurrent_vector进行此操作,它提供了同步增长功能。 This topic列出了每个并发容器。

请注意,这些在英特尔的TBB中也有相同的语法和语义,因此可以跨平台使用。

相关问题