2009-08-02 10 views
6

Si se define un mutex dentro de una función, ¿su bloqueo se aplica a funciones llamadas desde esa función? es decir,¿Se aplica también un bloqueo en un mutex a las funciones llamadas?

void f() { 
    Mutex mutex; 
    g(); 
} 

¿El bloqueo aún se aplica a las modificaciones de datos en g()?

Además, ¿tengo razón al decir que un bloqueo definido en un método de clase solo se aplicará a instancias específicas de esa clase? Significado:

Class Foo; 
Foo foo1, foo2; 
(In thread 1) foo1.bar(); 
(In thread 2) foo2.bar(); 

¿Cada llamada podría ocurrir al mismo tiempo?

Sería una buena ventaja si alguien pudiera explicar/señalar enlaces que explican el mecanismo detrás de mutexes. ¡Gracias! Actualmente estoy trabajando con la biblioteca Thread de Qt, si esa información ayuda.

Respuesta

15

En su ejemplo, en realidad no bloquea el mutex, por lo que no impedirá que diferentes subprocesos accedan a la función al mismo tiempo. También declara el mutex localmente dentro de la función, de modo que cada llamada de función usa un objeto mutex local diferente. Incluso si este mutex estuviera bloqueado, cada llamada de función bloquearía un objeto mutex diferente, sin impedir el acceso simultáneo.

Una mejor estrategia sería una configuración como esta:

class A { 
    QMutex mutex; 

    void f() { 
    QMutexLocker ml(mutex); // Acquire a lock on mutex 
    g(); 

    // The lock on the mutex will be released when ml is destroyed. 
    // This happens at the end of this function. 
    } 

    // ... 
}; 

En este caso mutex está bloqueado mientras exista ml, así también durante el tiempo que el hilo pasa dentro g(). Si otro hilo llamaría al f() durante este tiempo bloquearía la creación de su objeto ml hasta que el primer hilo salga de la función y el nuevo hilo pueda obtener el bloqueo en mutex.

+1

+1 usando QT api –

7

Un mutex es algo que agarras, y detendrá todos los otros hilos que intenten agarrarlo hasta que lo sueltes del hilo de agarre.

En su pregunta, tiene una función f asignando una instancia Mutex. Eso no es suficiente para bloquearlo. Tienes que llamar específicamente a mutex.lock() (en Qt, pero también en general, a menos que uses pthread, en ese caso usa pthread_mutex_lock y diviértete con cosas de bajo nivel que dependen de la plataforma. Qt lo resume muy bien).

He aquí un ejemplo con Qt

void MyClass::doStuff(int c) 
    { 
     mutex.lock(); 
     a = c; 
     b = c * 2; 
     mutex.unlock(); 
    } 

Una vez que obtenga el bloqueo, la llamada ag() se hará desde el hilo que consiguió el bloqueo, por lo que será solo en esa llamada asumiendo que no está llamando g() desde otros subprocesos de otra parte del código. Bloquear no significa que detendrá todos los otros hilos. Detienerá los hilos que intenten obtener el mismo bloqueo, hasta que se suelte el bloqueo.

Si esa es la única forma en que tus hilos llegan a g(), entonces estás sincronizado en ese acceso.

Para la segunda parte de su pregunta, si el mutex es un atributo de instancia, entonces serán dos mutexes diferentes. Deberá declarar y crear instancias de una instancia mutex de clase y remitir a foro a su bloqueo. En ese caso, cualquier intento de invocar un método en la clase que bloquea el mutex de clase se sincronizará efectivamente, lo que significa que no habrá dos subprocesos que ejecutarán ese método juntos.

Por ejemplo (no tengo Qt, así que no puedo compilar este código, y dejé de codificación con él hace 2 años, por lo que no podía trabajar)

class Foo { 
public: 
    void method(void) { 
     mutex.lock(); 
     cout << "method called"; 
     // long computation 
     mutex.unlock(); 
    } 

private: 
    QMutex mutex; 
}; 

Ok, en este caso, supongamos que tiene dos hilos, 1 y 2, y dos instancias de la clase Foo, a y b. Supongamos que el hilo 1 llama a.method() y el hilo 2 llama a b.method(). En este caso, los dos mutexes son instancias diferentes, por lo que cada subproceso ejecutará la llamada, de forma independiente, y se ejecutará en paralelo.

Supongamos que tiene dos hilos, 1 y 2, y una instancia de la clase Foo que se comparte entre los dos hilos. si el hilo 1 llama a.method() y luego el hilo 2 llama a.method(), el hilo 2 se detendrá y esperará hasta que se libere el bloqueo del mutex.

Por último,

class Foo { 
public: 
    void method(void) { 
     mutex.lock(); 
     cout << "method called"; 
     // long computation 
     mutex.unlock(); 
    } 

private: 
    static QMutex mutex; 
}; 

QMutex Foo::mutex; 

En este caso, el mutex es una variable estática clase. Solo tiene una instancia del mutex para cada instancia de objeto. Supongamos que tiene la misma situación que el primer caso anterior: dos hilos y dos instancias. En este caso, cuando el segundo subproceso intente llamar a b.method() tendrá que esperar a que a.method() se complete con el primer subproceso, ya que el bloqueo ahora es único y se comparte entre todas las instancias de su clase.

Para obtener más información, Qt tiene un buen tutorial sobre multithreading

https://doc.qt.io/qt-5/threads.html

+0

lo siento, hice un muy mal intento de pseudocódigo. Solo lo arregle. Tu respuesta para la primera parte fue exactamente lo que me preguntaba, ¡gracias! – int3

2

Su exclusión mutua se instatiated a nivel local, en la pila. Por lo tanto, una llamada a f() desde un hilo se bloqueará con su propia instancia del mutex. Cualquier otra llamada a f() desde otro hilo se bloqueará. ¡Entonces podría ocurrir una condición de carrera con los datos a los que se accede desde g()! Incluso es difícil llamarlo en la misma instancia de clase:

MyClass foo; 
(In thread 1) foo->f(); 
(In thread 2) foo->f(); 

Cómo manejar el bloqueo depende de lo que desee hacer. Según lo que usted dijo, supongo que una mejor política sería modificar la implementación de g() directamente: debe bloquear un mutex declarado como global por ejemplo, o como estático en g() para ser compartido entre cualquier llamada a g(). ¿Siempre y cuando entiendo que quieres bloquear tus datos globalmente?

+0

así que si tengo datos Quiero bloquear en instancias específicas de Foo :: f(), ¿debería instanciar el mutex como datos de clase no estáticos? – int3

+0

Bueno, supongo que debería hacer el truco. THen cualquier llamada de la instancia 'foo' de cualquier hilo en mi ejemplo evitará el acceso simultáneo. (Pero no desde 2 instancias diferentes por supuesto) –

Cuestiones relacionadas