简体   繁体   中英

Force copy (then destroy) on move-only type

Consider the following function of a lock-free work-stealing (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? 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])}; 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.

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; any others who lose the race would fail the compare_exchange_weak() . Thus, the operation doesn't break the semantics of a moveable only T as far as the user is concerned. 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).

One way to do this would be make copy constructor and copy assignment private members of T and have a friend WorkStealQ . The problem is what to do in the case of third-party library classes I may want to use as 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.

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. 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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