Tengo una función que varios hilos pueden llamarlo simultáneamente. Esta función tiene un argumento de entrada. Por ejemplo, considere la siguiente función:

bool MyClass::run(QString moduleName)
{
    qDebug() << QThread::currentThreadId();
    ...
}

Tengo dos opciones para usar esta función. Primero puedo usar un mutex dentro de la función de ejecución como a continuación:

...
run("Reza"); // can be different for different threads
...
bool MyClass::run(QString moduleName)
{
    qDebug() << QThread::currentThreadId();
    QMutexLocker locker(&runMutex);
    ...
}

El segundo es usar un mutex cuando se llama a esta función como a continuación:

...
runMutex.lock();
run("Reza"); // can be different for different threads
runMutex.unlock();
...
bool MyClass::run(QString moduleName)
{
    qDebug() << QThread::currentThreadId();
    ...
}

¿Cuál es correcto y mejor? ¿El argumento de entrada (moduleName) cambia en la primera opción? (Quiero decir, al llamar al hilo pasar un argumento diferente a esta función)

Gracias de antemano por su ayuda. Reza

0
Reza 26 dic. 2016 a las 15:30

3 respuestas

La mejor respuesta

¡En muchos contextos tiene sentido tener ambos ! La función de adquirir un mutex internamente hace que el uso de esta función sea más fácil y generalmente más seguro de usar. Sin embargo, cuando use mutexes explícitamente, es bastante común que desee realizar operaciones adicionales además de las realizadas por el método run() mientras mantiene el bloqueo. En ese caso, tendría otra función que adquiera el bloqueo y que no pueda llamar a la función de bloqueo interno (bueno, a menos que el mutex sea un mutex recursivo que realmente no creo que sea una buena idea). La salida es tener una versión de la función, por ejemplo, run_locked() o una versión con diferentes parámetros que asume que se adquiere el bloqueo.

Cuando uso el bloqueo explícito (generalmente trato de evitar hacerlo porque no puedo razonar sobre el código que usa bloqueos) me pareció útil tener pares de funciones correspondientes como esta (normalmente usaría las instalaciones std):

bool MyClass::run(QString moduleName) {
    QMutexLocker kerberos(&runMutex);
    return this->run(kerberos, moduleName);
}
bool MyClass::run(QMutexLocker& kerberos, QString moduleName) {
    // do whatever work is needed here
}

Al pasar el objeto de bloqueo, se asegura que haya un protector adquirido, es decir, un usuario no puede simplemente llamar a la función esperando que el bloqueo se adquiera sin ningún bloqueo de bloqueo adquirido. Existe un mal uso potencial al adquirir una protección de bloqueo para el bloqueo incorrecto.

1
Dietmar Kühl 26 dic. 2016 a las 12:43

Tanto el método es correcto, pero el primero es un método mejor. También le da legibilidad al código.

En la primera opción, los argumentos del argumento de entrada (variable local) siempre son seguros porque cada subproceso tiene su propia pila.

1
magesh gopal 26 dic. 2016 a las 12:42

Dietmar Kühl proporcionó una buena respuesta para elegir entre los enfoques mencionados. Sin embargo, quiero agregar que minimizar la sección crítica siempre es una buena práctica. Entonces, si no necesita bloquear toda la función "run ()", no debe usar ninguno de los métodos mencionados, sino proteger la sección crítica más pequeña posible dentro de "run ()".

1
nnovich-OK 26 dic. 2016 a las 13:02