简体   繁体   English

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

[英]Force copy (then destroy) on move-only type

Consider the following function of a lock-free work-stealing (de)que: 考虑以下无锁工作窃取(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();
}

But what if T is only moveable but non-copyable? 但是,如果T仅可移动但不可复制该怎么办? The issue is that the reading of the item from the buffer is a copy operation, and cannot be changed to auto task{std::move(_tasks[tail & _mask])}; 问题是从缓冲区读取项目是一项复制操作,无法更改为auto task{std::move(_tasks[tail & _mask])}; because another concurrent operation could also move it, in which case any move constructor which is not read-only but also modifies the original (such as nulling some pointer to a resource) would break the algorithm. 因为另一个并发操作也可以移动它,在这种情况下,任何非只读但又修改原始操作的move构造函数(例如,使指向资源的指针为空)都会破坏算法。

Note that the overall semantics of Steal() do perform only a move from an external point of view, since only one concurrent operation will return with the T that was stored at that location; 请注意, Steal()的整体语义仅从外部角度执行一次移动,因为只有一个并发操作将返回存储在该位置的T并返回。 any others who lose the race would fail the compare_exchange_weak() . 输掉比赛的其他任何人都将使compare_exchange_weak()失败。 Thus, the operation doesn't break the semantics of a moveable only T as far as the user is concerned. 因此,就用户而言,该操作不会破坏仅可移动T的语义。 Unfortunately, internally it needs to make a temporary shallow copy of T until it determines whether to complete it as a move or give up, leaving it in the buffer (it's basically a two-phase move with a check occurring in the middle). 不幸的是,在内部,它需要制作一个临时的T浅拷贝,直到确定是将其完成还是放弃后再将其保留在缓冲区中(这基本上是两阶段移动,中间进行检查)。

One way to do this would be make copy constructor and copy assignment private members of T and have a friend WorkStealQ . 一种实现方法是使T副本构造函数和副本分配私有成员,并拥有一个friend WorkStealQ The problem is what to do in the case of third-party library classes I may want to use as T . 问题是在我可能想用作T的第三方库类的情况下该怎么做。 Is there any other option in that case than just using pointers to such objects rather than storing them intrusively (and thus getting a performance hit)? 在那种情况下,除了使用指向此类对象的指针而不是侵入性地存储它们(从而导致性能下降)之外,还有其他选择吗? I'm assuming memcpy won't work even for a shallow copy in the case of classes with virtual functions. 我假设对于带有虚函数的类,即使对于浅表副本, memcpy也无法使用。

I think your best bet might be to have a separate shallow_copy class that is defined explicitly for each T, and use that in your work-stealing function. 我认为最好的选择可能是为每个T显式定义一个单独的shallow_copy类,并在工作窃取函数中使用该类。 That will also allow you to deal with whatever issues cause your type to be move-only (as you can't know a priori that a temporary copy will avoid those issues). 这也将使您能够处理任何导致您的类型变为仅移动的问题(因为您无法先验地知道临时副本可以避免这些问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM