Tenir compte de la fonction suivante d'un travail vol sans blocage (de) Que:Force de copie (puis détruire) sur le mouvement-seul type
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();
}
Mais si T
est seulement mobile mais non copiable? Le problème est que la lecture de l'élément à partir du tampon est une opération de copie et ne peut pas être modifiée en auto task{std::move(_tasks[tail & _mask])};
car une autre opération simultanée pourrait également la déplacer, auquel cas tout constructeur de déplacement qui n'est pas en lecture seule modifie également l'original (comme annuler un pointeur sur une ressource) casserait l'algorithme.
Notez que la sémantique globale de Steal()
ne réalisent qu'un mouvement d'un point de vue externe, étant donné qu'une seule opération simultanée sera de retour avec le T
qui a été stocké à cet endroit; tous les autres qui perdent la course échoueront compare_exchange_weak()
. Ainsi, l'opération ne casse pas la sémantique d'un mobile seulement T
en ce qui concerne l'utilisateur. Malheureusement, en interne, il doit faire une copie superficielle temporaire de T
jusqu'à ce qu'il détermine s'il faut le compléter comme un mouvement ou abandonner, le laissant dans le tampon (c'est fondamentalement un mouvement en deux phases avec une vérification se produisant au milieu).
Une façon de le faire serait de faire un constructeur de copie et de copier des membres privés d'affectation de T
et d'avoir un friend WorkStealQ
. Le problème est ce qu'il faut faire dans le cas de classes de bibliothèques tierces que je souhaite utiliser comme T
. Y a-t-il une autre option dans ce cas que d'utiliser simplement des pointeurs sur de tels objets plutôt que de les stocker de manière intrusive (et ainsi obtenir un hit de performance)? Je suppose que memcpy
ne fonctionnera pas même pour une copie superficielle dans le cas de classes avec des fonctions virtuelles.
Ce sont des moments comme celui-ci que je pense au conseil de mon vieux vieux Tony; la première règle de la programmation sans verrou? Ne pas. – Yakk