c++ multithreading qt mutex qmutex

c++ - ¿Cómo usar QMutex?



multithreading qt (3)

Soy novato en Qt y estoy buscando multihilo en Qt.
Como aprendí en Documentos Qt , definí dos clases para dos hilos:

#include <QThread> #include <QMutex> class thread_a : public QThread { Q_OBJECT public: explicit thread_a(QObject *parent = 0); int counter; protected: void run(); };

Y en el archivo CPP:

#include "thread_a.h" thread_a::thread_a(QObject *parent) : QThread(parent) { counter=0; } void thread_a::run() { counter++; }

La segunda clase de subprocesos es la misma, pero con el método counter-- en run()
Luego ejecuto estos dos hilos de main.ccp .

Ahora mi pregunta:
¿Cómo puedo compartir el counter en thread_a y thread_b usando QMutex ?


Bien, gracias especiales a @skyhisi por la gran solución para un proyecto real.

Leí la publicación @skyhisi y más artículos sobre QMutex y cómo compartir variables. Para fines educativos, implementé una muestra simple / clara del uso de QMutex para compartir la variable (este counter casos).

class thread_a : public QThread { Q_OBJECT public: thread_a(QMutex*, int*); void shutdown(); private: QMutex* mutex; int* counter; bool isShutdownRequested; protected: void run(); };

y en el archivo thread_a.cpp :

thread_a::thread_a(QMutex * m, int* i) { counter=i; isShutdownRequested=false; mutex=m; } void thread_a::run() { isShutdownRequested=false; forever{ //lock mutex for changing in shared variable mutex->lock(); *counter=*counter+1; mutex->unlock(); if(isShutdownRequested) break; } } void thread_a::shutdown() { isShutdownRequested=true; }

En la myMainWindow::RunThreads(bool bl) :

int cnt=0; QMutex mu; thread* a=new thread_a(&mu, &cnt); thread* b=new thread_b(&mu, &cnt); a.start(); b.start();

En myMainWindow::~myMainWindow() deconstructor:

a->shutdown(); b->shutdown();

Gracias de nuevo @skyhisi


En lugar de tener los datos dentro de un hilo, mueva los datos fuera del hilo, protéjalos y luego acceda a ellos desde ambos hilos.

El siguiente es un bosquejo, de lo que podrías hacer:

class Counter { public: Counter():mMutex(),mCounter(0){} int inc() { QMutexLocker ml(&mMutex); return mCounter++; } int dec() QMutexLocker ml(&mMutex); return mCounter--; } private: QMutex mMutex; int mCounter; Q_DISABLE_COPY(Counter) }; class ThreadA : public QThread { public: ThreadA(Counter* ctr); /* ... */ }; class ThreadB : public QThread { public: ThreadB(Counter* ctr); /* ... */ };

El constructo de Counter menudo se conoce como un Monitor , de Wikipedia (el énfasis es mío):

En la programación concurrente, un monitor es un objeto o módulo destinado a ser usado de manera segura por más de un hilo. La característica definitoria de un monitor es que sus métodos se ejecutan con exclusión mutua. Es decir, en cada momento, como máximo, un hilo puede estar ejecutando cualquiera de sus métodos. Esta exclusión mutua simplifica en gran medida el razonamiento sobre la implementación de monitores en comparación con el razonamiento sobre el código paralelo que actualiza una estructura de datos .

En este caso específico, una construcción más eficiente sería QAtomicInt . Esto gana atomicidad por su uso de instrucciones especiales de CPU. Esta es una clase de bajo nivel que podría usarse para implementar otras construcciones de subprocesos.

Editar - Ejemplo completo

Usar hilos con el estado compartido correctamente no es trivial. Es posible que desee considerar el uso de señales / ranuras Qt con conexiones en cola u otros sistemas basados ​​en mensajes.

Alternativamente, otros lenguajes de programación como Ada admiten subprocesos y monitores (objetos protegidos) como construcciones nativas.

Aquí hay un ejemplo completo de trabajo. Este es solo un código de muestra, no use QTest::qSleep en código real.

objs.h

#ifndef OBJS_H #define OBJS_H #include <QtCore> class Counter { public: Counter(int init); int add(int v); private: QMutex mMutex; int mCounter; Q_DISABLE_COPY(Counter) }; class CtrThread : public QThread { Q_OBJECT public: CtrThread(Counter& c, int v); void stop(); protected: virtual void run(); private: bool keeprunning(); Counter& mCtr; int mValue; bool mStop; QMutex mMutex; }; #endif

objs.cpp

#include "objs.h" Counter::Counter(int i): mMutex(), mCounter(i) {} int Counter::add(int v) { QMutexLocker ml(&mMutex); return mCounter += v; } /////////////////////////////////////// CtrThread::CtrThread(Counter& c, int v): mCtr(c), mValue(v), mStop(false), mMutex() {} void CtrThread::stop() { QMutexLocker ml(&mMutex); mStop = true; } void CtrThread::run() { while(keeprunning()) { mCtr.add(mValue); } } bool CtrThread::keeprunning() { QMutexLocker ml(&mMutex); return ! mStop; }

test.cpp

#include <QtCore> #include <QTest> #include "objs.h" int main(int argc, char** argv) { QCoreApplication app(argc, argv); qDebug() << "Initalising"; Counter ctr(0); CtrThread thread_a(ctr, +1); CtrThread thread_b(ctr, -1); qDebug() << "Starting Threads"; thread_a.start(); thread_b.start(); for (int i = 0; i != 15; ++i) { qDebug() << "Counter value" << ctr.add(0); QTest::qSleep(1000); } qDebug() << "Stopping Threads"; thread_a.stop(); thread_b.stop(); thread_a.wait(); thread_b.wait(); qDebug() << "Finished"; return 0; }

test.pro

QT=core testlib HEADERS=objs.h SOURCES=test.cpp objs.cpp

Compilar y ejecutar, verá el valor que se está imprimiendo, salida de muestra:

Initalising Starting Threads Counter value 0 Counter value 11057 Counter value 28697 Counter value 50170 Counter value 60678 Counter value 73773 Counter value 84898 Counter value 96441 Counter value 118795 Counter value 135293 Counter value 146107 Counter value 158688 Counter value 169886 Counter value 201203 Counter value 212983 Stopping Threads Finished


Escribo un ejemplo simple que hace referencia a la "ayuda" de QMutex, en la que dos hilos cambian un mismo número (como un Monitor). También refiera el código de SMMousavi. Aquí está el código:

//main.cpp

#include <QCoreApplication> #include "method.h" int aNum=0; QMutex aMutex; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); int *p_no= &aNum; QMutex *p_Mu = &aMutex; method mThread1(p_Mu, p_no); method mThread2(p_Mu, p_no); mThread1.name = "one"; mThread2.name = "two"; mThread1.start(); mThread2.start(); return a.exec(); }

// metodo.h

#ifndef METHOD_H #define METHOD_H #include <QDebug> #include <QThread> #include <QtCore> #include <QString> #include <QMutex> class method: public QThread { public: method(QMutex *mu, int *nu); void run(); void method1(); void method2(); QString name; private: int *number; QMutex *myMutex; }; #endif // METHOD_H

//method.cpp #include "method.h"

method::method(QMutex *mu, int *nu) { myMutex = mu; number = nu; } void method:: run() { for (int i = 0; i<100; i++) { if(this->name == "one" ) { this->method1(); } else { this->method2(); } } } void method::method1() { myMutex->lock(); *number += 1; qDebug()<<*number<<"---"<<this->name; myMutex->unlock(); } void method ::method2() { myMutex->lock(); *number -= 1; qDebug()<<*number<<"---"<<this->name; myMutex->unlock(); }