2017-09-11 8 views
2

Impossible de faire cela (voir le code) pour une raison quelconque. Documentation regardé, il ne semble pas être une raison de ne pas travailler ...Problème avec les structures std :: atomic et custom

struct vector { 
    float x, y, z; 
}; 
std::atomic<vector> Name = {0}; 

Il dit que je ne peux pas l'initialiser avec une liste d'initialiseur, et quand je vais l'utiliser dans mon code, il dit qu'il n'a pas de membres.

Name.x = 4.f; 
Name.y = 2.f * Name.x; 
Name.z = 0.1f; 

Répondre

-1

Il est Name._My_val.x, Name._My_val.y, Name._My_val.z pas Name.x, Name.y, Name.z

Pourquoi est-il que personne ne me dit ça me dépasse, mais peu importe.

+0

Non, ce n'est pas le cas.Ce que vous faites ici, c'est jouer avec un détail d'implémentation interne. Cela ne fonctionnera pas comme prévu. –

+0

Vous contournez la barrière de mémoire. Ces opérations ne seront pas atomiques. –

+1

Voulez-vous une structure avec des membres atomiques séparés, ou voulez-vous que la structure entière agisse comme un seul objet atomique? Quoi qu'il en soit, cela ne se compile que sur MSVC, où une structure de 12 octets n'est pas sans verrou, ce qui brise l'atomicité des autres opérations atomiques. https://godbolt.org/g/ji6ABT ** Il ne compile même pas sur d'autres compilateurs. ** –

3

Une instance de std::atomic<vector> n'est pas une instance de vector. Il n'a pas x, y, ou z comme membres. Ce qu'il a (conceptuellement, en interne) est une instance de vector. Mais vous ne pouvez pas y accéder avec l'opérateur . parce que cela casserait l'atomicité, qui est, comme, le point de std::atomic. (Ceci est également la raison pour laquelle vous ne pouvez pas utiliser une liste de initialiseur.)

Pour accéder à la substance vector, utilisez load() et store():

//atomically load a snapshot of Name 
auto name_snapshot = Name.load(); //name_snapshot is a vector instance 
name_snapshot.x = 4.f; 
name_snapshot.y = 2.f * name_snapshot.x; 
name_snapshot.z = 0.1f; 
//now atomically store it: 
Name.store(name_snapshot); 
+0

Bon exemple '.load()' et '.store'. Probablement une bonne idée de souligner n'est pas ce n'est pas un RMW atomique; vous devrez utiliser une boucle CAS pour cela. C'est seulement une charge atomique et un magasin atomique inconditionnel qui pourrait marcher sur les mises à jour d'autres threads. –

+0

En outre, le seul problème avec l'initialiseur est manquant un niveau d'accolades: 'std :: atomic Name = {{0,0,0}};' compile juste bien (https://godbolt.org/g/o5PdVF), ainsi que d'autres moyens d'avoir des arguments avant atomiques 'depuis son constructeur [(non atomique)] (http://en.cppreference.com/w/cpp/atomic/atomic/atomic) vers le' T() 'constructeur, comme' std :: atomique Name2 {{1.0,1.0,2.0}}; ' –

+0

puis-je, à mon tour, faire quelque chose comme ça? 'Name.store ({0, 0, 0})' ou devrais-je créer une variable réelle? – vidsac

2

Il y a documentation std::atomic<> ici http://en.cppreference.com/w/cpp/atomic/atomic

Il y a aucun membre x, y et z sur std::atomic<>.

std::atomic<X> est un type dans lequel le entier X peut être remplacé de manière atomique, et non des parties individuelles de celui-ci. Ce que vous voulez probablement est un mutex, puisque pour une structure comme name_snapshot, std :: atomic utilisera un mutex dans tous les cas. Comme il est peu probable qu'une instruction atomique soit disponible, gérer un chargement/stockage atomique de la structure entière.

+0

Sur certains compilateurs, par exemple gcc ou clang ciblant x86-64, 'atomic ' est verrouillé pour T jusqu'à 16 octets. Il doit utiliser 'lock cmpxchg16b' même pour' .load() 'ou' .store() ', mais ce n'est pas très efficace. (Et pour cette raison, gcc7 et plus tard renvoie false pour '.is_lock_free()', et n'introduit pas le 'cmpxchg16b' de verrouillage, mais appelle toujours une fonction de bibliothèque https://gcc.gnu.org/ml/ gcc-patches/2017-01/msg02344.html Même si l'implémentation actuelle de la bibliothèque est sans verrou, et ne peut pas être changée sans rompre la compatibilité avec le code qui contient 'lock cmpxchg16b') –