une fonction de lecture nécessite-t-elle un mutex?

J’ai une classe qui est accessible à partir de plusieurs threads. Les fonctions getter et setter sont protégées par des verrous. Les verrous pour les fonctions de lecture sont-ils vraiment nécessaires? Pourquoi?

class foo { public: void setCount (int count) { boost::lock_guard lg(mutex_); count_ = count; } int count () { boost::lock_guard lg(mutex_); // mutex needed? return count_; } private: boost::mutex mutex_; int count_; }; 

Le seul moyen de contourner le locking est de vous convaincre que le système transfère la variable protégée de manière atomique dans tous les cas. Si vous ne pouvez pas en être sûr pour une raison ou une autre, vous aurez besoin du mutex.

Pour un type simple comme un int, vous pourrez peut-être vous en convaincre, en fonction de l’architecture et en supposant qu’il soit correctement aligné pour le transfert d’instructions uniques. Pour tout type plus compliqué que cela, vous devrez avoir le verrou.

Le mutex ne protège-t-il vraiment qu’un seul int ? Cela fait une différence – s’il s’agit d’un type de données plus complexe, vous devez absolument le verrouiller.

Mais s’il ne s’agit que d’un int et que vous êtes certain qu’il s’agit d’un type atomique (le processeur n’aura pas à effectuer deux lectures de mémoire distinctes pour charger l’int dans un registre), et vous avez analysé les performances et déterminé le résultat. besoin de meilleures performances, alors vous pouvez envisager de supprimer le verrou du getter et du passeur. Si vous faites cela, assurez-vous de qualifier le int comme volatile . Et écrivez un commentaire expliquant pourquoi vous n’avez pas de protection mutex et dans quelles conditions vous en auriez besoin si la classe change.

Aussi, méfiez-vous que vous n’avez pas de code comme celui-ci:

 void func(foo &f) { int temp = f.count(); ++temp; f.setCount(temp); } 

Ce n’est pas threadsafe, que vous utilisiez un mutex ou non. Si vous avez besoin de faire quelque chose comme ça, la protection mutex doit être en dehors des fonctions setter / getter.

Si vous n’avez pas de mutex autour du getter et qu’un thread le lit pendant qu’un autre thread l’écrit, vous obtiendrez des résultats amusants.

dans votre cas, probablement pas, si votre cpu est 32 bits, cependant si count est un object complexe ou si cpu a besoin de plus d’une instruction pour mettre à jour sa valeur, alors oui

Le verrou est nécessaire pour sérialiser l’access à une ressource partagée . Dans votre cas spécifique, vous pouvez vous contenter d’ opérations entières atomiques, mais en général, pour les objects plus volumineux nécessitant plus d’une transaction par bus, vous avez besoin de verrous pour garantir que le lecteur voit toujours un object cohérent .

Cela dépend de l’implémentation exacte de l’object à verrouiller. Cependant, en général, vous ne voulez pas que quelqu’un modifie (définisse?) Un object pendant que quelqu’un d’autre est en train de le lire (l’obtenir?). Le moyen le plus simple d’éviter cela est de le faire verrouiller par un lecteur.

Dans des configurations plus complexes, le verrou sera implémenté de manière à ce que plusieurs personnes puissent lire en même temps, mais personne ne puisse écrire pendant que quelqu’un lit, et personne ne peut lire pendant qu’une écriture est en cours.