J'ai trouvé que les shared_ptr et weak_ptr, un long avec une liste, faisaient le travail dont j'avais besoin. Mon problème était que j'avais plusieurs clients qui voulaient interagir avec les données internes d'un hôte. Typiquement, l'hôte met à jour les données par lui-même, cependant, si un client le demande, l'hôte doit arrêter la mise à jour jusqu'à ce qu'aucun client n'accède aux données de l'hôte. En même temps, un client peut demander un accès exclusif, de sorte qu'aucun autre client, ni l'hôte, ne puisse modifier les données de l'hôte.
Pour ce faire, j'ai créé une structure :
struct UpdateLock
{
typedef std::shared_ptr< UpdateLock > ptr;
};
Chaque client aurait un membre de ce type :
UpdateLock::ptr m_myLock;
L'hôte aurait alors un membre weak_ptr pour l'exclusivité, et une liste de weak_ptrs pour les verrous non exclusifs :
std::weak_ptr< UpdateLock > m_exclusiveLock;
std::list< std::weak_ptr< UpdateLock > > m_locks;
Il existe une fonction pour activer le verrouillage, et une autre pour vérifier si l'hôte est verrouillé :
UpdateLock::ptr LockUpdate( bool exclusive );
bool IsUpdateLocked( bool exclusive ) const;
Je teste les verrous dans LockUpdate, IsUpdateLocked, et périodiquement dans la routine de mise à jour de l'hôte. Tester un verrou est aussi simple que de vérifier si le weak_ptr a expiré, et de supprimer tout expiré de la liste m_locks (je ne le fais que pendant la mise à jour de l'hôte), je peux vérifier si la liste est vide ; en même temps, j'obtiens un déverrouillage automatique quand un client réinitialise le shared_ptr auquel il est accroché, ce qui arrive aussi quand un client est détruit automatiquement.
L'effet global est que, puisque les clients ont rarement besoin d'exclusivité (généralement réservée aux ajouts et aux suppressions), la plupart du temps, une demande de LockUpdate( false ), c'est-à-dire de non-exclusivité, aboutit tant que ( ! m_exclusiveLock). Et une demande de LockUpdate( true ), c'est-à-dire d'exclusivité, ne réussit que si à la fois ( ! m_exclusiveLock) et (m_locks.empty()).
Une file d'attente pourrait être ajoutée pour atténuer les collisions entre les verrous exclusifs et non exclusifs, mais comme je n'ai pas eu de collisions jusqu'à présent, j'ai l'intention d'attendre que cela se produise pour ajouter la solution (surtout pour avoir une condition de test réelle).
Jusqu'à présent, cela fonctionne bien pour mes besoins ; je peux imaginer la nécessité d'étendre ce système et les problèmes qui pourraient survenir en cas d'utilisation étendue, mais cela a été rapide à mettre en œuvre et a nécessité très peu de code personnalisé.
1 votes
Peut-être utiliser la condition mutex et std::promise et std::future ?