2
Pseudocode:
Function1_vector_copy () {
vectora = vectorb;
}
Function2_vector_search() {
find k in vectora;
}

该程序是多线程的。虽然可以搜索多个线程,但矢量复制仅由单个线程完成,但有时会发生。问题是无论如何,vector_search 不应该失败。Vector_copy 可以延迟,但 vector_search 不应该。它是一个没有延迟,没有失败的模式。问题是共享变量 vectora 必须是持久的,因此 vector_search 根本不会失败。实现这一目标的最佳方法是什么?

编辑 :

使用另一个问题的答案

boost::shared_mutex _access;

Function1_vector_copy() {

  // get upgradable access
  boost::upgrade_lock lock(_access);

  // get exclusive access
  boost::upgrade_to_unique_lock uniqueLock(lock);
  // now we have exclusive access

  vectora.swap(vectorb);
}

Function2_vector_search() {

  // get shared access
  boost::shared_lock lock(_access);

  // now we have shared access

  find k in vectora ;

}

如果具有可升级所有权的线程尝试升级而其他线程具有共享所有权,则尝试将失败并且线程将阻塞,直到可以获得独占所有权。 --boost 文档

诀窍是矢量复制是异步完成的,它将在获得独占所有权后发生。所以向量复制最终会发生,但延迟了,实际上向量复制也是一个非失败操作,但延迟了,这对我来说没问题。会有一个锁以某种方式进行同步,我们将至少阻塞一毫秒。但是使用这种交换的优势将导致它的时间更短,可以忽略不计。

4

2 回答 2

2
Function1_vector_copy () 
{
    VectorType tmp = vectorb;

    rwLock.acquireWrite();
    swap(tmp,vectora);
    rwLock.releaseWrite();
}

其余的留给读者练习。

更新:总结下面的评论......

首先我要明确的是,swap(...)上面的原始调用是伪代码,不一定要按字面意思理解。我不知道到底是什么VectorType(技术上仍然不知道)。我假设您打算尽可能高效地进行 swap() 。毕竟是伪代码...

无论如何,std::swap()它专门用于 C++ 标准库中的所有容器类型。所以 if VectorTypeis 实际上std::vector<UDT>, thenswap(tmp,vectora);应该是最佳的并且无需修改即可工作(依靠 Koenig 查找来解析符号)。

于 2012-01-30T21:31:15.040 回答
2

我认为 mcmcc 的想法并不太远,而是将执行矢量复制的通用 std::swap(),您应该能够使用 std::vector::swap()。从功能上讲,vector 的交换函数与通用函数的工作方式相同,但它要快得多,因为它只交换很少的指针/大小变量并且实际上并不进行元素复制。因此,您的锁只会在很少的组装说明中出现。

如果这仍然太长(此时,您可能想要查看您的设计),另一种选择是拥有一个永远不会相互替换的向量的循环列表。取而代之的是另一个引用“活动”向量的指针。当您需要修改该集合时,初始化圆圈中的下一个向量,初始化完成后,更新指针。使用此解决方案,根本没有锁。前一刻你的读者使用一个向量,下一刻他们使用不同的向量。

第二种解决方案的缺点是它肯定需要更多的内存,而且有点不可预测。我想你可以声明你的“活动”向量指针volatile,这将强制 CPU 确保每次读取指针值时缓存都是同步的,否则,会有一些不确定的元素,其中多个 CPU 内核可能正在查看 main 的不同快照记忆。同样没有任何同步,您如何确保其他线程完成即将被吹走的向量?而且,如果您进行任何类型的同步,您将返回 RW 锁。

虽然我认为你可以让第二种选择工作并且相对稳定地进行一些调整......可能。我的第一反应是使用 RW lock 和 vector::swap()。

更新:实际上,我只是重新阅读了规范,看起来 STL 确实专门针对容器(包括 std::vector)专门针对全局 std::swap。所以即使调用全局函数,复杂度也是 O(1)。mcmcc 的答案有效。

所以我们放下这个猜测,我只写了一点代码,并用调试器逐步完成。这是我的应用程序代码:

std::vector< int >      a, b;

for( int i = 0; i < 10; i++ )
{
    a.push_back( i );
    b.push_back( i * 10 );
}

std::swap( a, b );

以下是对 std::swap 的全局通用版本的调用中的内容:

template<class _Ty,
class _Alloc> inline
void swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right)
{   // swap _Left and _Right vectors
_Left.swap(_Right);
}

如您所见,通用 std::swap 模板函数在通用模式下执行复制构造函数,专门用于向量。在内部,它只是将所有工作委托给 std::vector::swap(),正如我们所建立的那样,它是一个更快的变体。

于 2012-01-31T07:36:56.620 回答