Comment puis-je assurer qu'il n'y a que 1 mutex?

voix
2

Je courais un fil de code en sécurité ici. J'utilise un mutex pour protéger la partie du code qui doit être exécuté que par seulement 1 fil à la fois. Le problème que j'ai utilise ce code parfois je me retrouve avec 2 objets Mutex. Ceci est une fonction statique par la manière. Comment puis-je assurer seulement 1 mutex est créé ??

/*static*/ MyClass::GetResource()
{

if (m_mutex == 0)
{
// make a new mutex object
m_mutex = new MyMutex();
}

m_mutex->Lock();
Créé 27/08/2009 à 02:23
source utilisateur
Dans d'autres langues...                            


5 réponses

voix
8

La question est le fil pourrait être interrompu après avoir vérifié si m_mutex est 0, mais pas avant qu'il ne crée le mutex, ce qui permet un autre thread à exécuter par le même code.

Ne pas céder à m_mutex tout de suite. Créer un nouveau mutex, puis faire un échange atomique comparer.

Vous ne mentionnez pas votre plate-forme cible, mais sous Windows:

MyClass::GetResource()
{
    if (m_mutex == 0)
    {
        // make a new mutex object
        MyMutex* mutex = new MyMutex();

        // Only set if mutex is still NULL.
        if (InterlockedCompareExchangePointer(&m_mutex, mutex, 0) != 0)
        {
           // someone else beat us to it.
           delete mutex;
        }
    }
    m_mutex->Lock();

Dans le cas contraire, remplacer par le comparer / fonction d'échange de votre plate-forme offre.

Une autre option consiste à utiliser l' initialisation unique support, qui est disponible sous Windows Vista et plus, ou tout simplement pré-créer le mutex si vous le pouvez.

Créé 27/08/2009 à 02:27
source utilisateur

voix
12

Il suffit de créer en m_mutexdehors de GetResource(),avant qu'il ne puisse jamais être appelé - cela supprime la section critique autour de la création effective du mutex.

MyClass::Init()
{
  m_mutex = new Mutex;
}    

MyClass::GetResource()
{
  m_mutex->Lock();
  ...
  m_mutex->Unlock();
}
Créé 27/08/2009 à 02:30
source utilisateur

voix
2

Pourquoi utiliser un pointeur de toute façon? Pourquoi ne pas remplacer le pointeur avec une instance réelle qui ne nécessite pas une gestion dynamique de la mémoire? Cela permet d'éviter la condition de la course, et ne pas imposer une baisse de performance sur chaque appel à la fonction.

Créé 27/08/2009 à 02:35
source utilisateur

voix
3

initialisation paresseuse mutex est pas vraiment approprié pour les méthodes statiques; vous avez besoin d'une garantie que les courses de personne pour l'initialisation. Ce qui suit utilise le compilateur pour générer un seul mutex statique pour la classe.

/* Header (.hxx) */
class MyClass
{
    ...

  private:
    static mutable MyMutex m_mutex;  // Declares, "this mutex exists, somewhere."
};


/* Compilation Unit (.cxx) */
MyMutex MyClass::m_mutex;            // The aforementioned, "somewhere."

MyClass::GetResource()
{
    m_mutex.Lock();
    ...
    m_mutex.Unlock();
}

D'autres solutions exigeront des hypothèses supplémentaires de vos collègues programmeurs. Avec la méthode « init call () », par exemple, vous devez être sûr que la méthode d'initialisation ont été appelés, et tout le monde devrait savoir cette règle.

Créé 27/08/2009 à 02:45
source utilisateur

voix
0

Comme il est seulement pour protéger une section spécifique du code, déclarer simplement statique à l'intérieur de la fonction.

static MyClass::GetResource()
{
    static MyMutex mutex;

    mutex.Lock();
    // ...
    mutex.Unlock();

La variable est une variable locale avec la durée de stockage statique. Il est explicitement indiqué dans la norme:

Une mise en œuvre est autorisé à effectuer au début de l'initialisation d'autres variables de portée de bloc avec la durée de stockage statique ou de fils dans les mêmes conditions que l'application est autorisée à initialiser statiquement une variable avec une durée de stockage statique ou de fil dans la portée de l'espace de nom (3.6.2). Dans le cas contraire une telle variable est initialisée la première commande le temps passe par sa déclaration; une telle variable est considéré comme initialisé lors de l'achèvement de son initialisation. Si les sorties d'initialisation en lançant une exception, l'initialisation est pas terminée, il sera jugé à nouveau le contrôle prochaine fois entre la déclaration. Si le contrôle entre la déclaration en même temps tandis que la variable est en cours d'initialisation, l'exécution simultanée doit attendre la fin de l'initialisation.

La dernière phrase est d'un intérêt particulier pour vous.

Créé 20/02/2014 à 13:09
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more