在仅移动类型上强制复制(然后销毁)

时间:2017-07-31 19:37:59

标签: c++ move-semantics shallow-copy

考虑以下无锁工作窃取(de)que的功能:

template<class T>
inline T WorkStealQ<T>::Steal(void)
{
    auto tail{_tail.load(std::memory_order_acquire)};
    if (_head.load(std::memory_order_acquire) <= tail) return T();
    auto task{_tasks[tail & _mask]};
    if (_tail.compare_exchange_weak(tail, tail + 1, std::memory_order_release, std::memory_order_relaxed)) return task;
    return T();
}

但如果T只能移动但不可复制呢?问题是从缓冲区读取项目是一个复制操作,并且不能更改为auto task{std::move(_tasks[tail & _mask])};,因为另一个并发操作也可以移动它,在这种情况下任何移动构造函数不是只读的,而且还修改原始文件(例如将某些指针置为资源)会破坏算法。

请注意,Steal()的整体语义只执行从外部角度的移动,因为只有一个并发操作将返回存储在该位置的T;任何输掉比赛的人都会失败compare_exchange_weak()。因此,就用户而言,操作不会破坏仅可移动T的语义。不幸的是,在内部它需要制作T的临时浅拷贝,直到它确定是将其作为移动还是放弃,将其留在缓冲区中(它基本上是一个两阶段移动的检查发生在中间)。

执行此操作的一种方法是使T的复制构造函数和副本分配私有成员具有friend WorkStealQ。问题是如果我想将第三方库类用作T,该怎么做。在这种情况下是否有任何其他选项,而不仅仅是使用指向这些对象的指针,而不是侵入性地存储它们(从而获得性能损失)?我假设memcpy即使对于具有虚函数的类的浅拷贝也不会工作。

1 个答案:

答案 0 :(得分:1)

我认为你最好的选择可能是为每个T明确定义一个单独的shallow_copy类,并在你的工作窃取函数中使用它。这也将允许您处理导致您的类型仅移动的任何问题(因为您无法事先知道临时副本将避免这些问题)。

相关问题