1. ホーム
  2. c++

[解決済み] QMutexの使用方法について教えてください。

2022-02-17 22:29:17

質問事項

私はQtの初心者で、Qtのマルチスレッドについて調べています。
で学んだように Qt ドキュメント 2つのスレッドに対して2つのクラスを定義しました。

#include <QThread>
#include <QMutex>

class thread_a : public QThread
{
    Q_OBJECT
public:
    explicit thread_a(QObject *parent = 0);
    int counter;

protected:
    void run();
};

そしてCPPファイルでは

#include "thread_a.h"

thread_a::thread_a(QObject *parent) :
    QThread(parent)
{
    counter=0;
}

void thread_a::run()
{
    counter++;
}

2つ目のスレッドクラスも同じですが counter--run() メソッドを使用します。
そして、この2つのスレッドを main.ccp .

さて、私の質問です。
を共有するにはどうすればよいですか? counterthread_athread_b を使って QMutex ?

解決方法は?

データをスレッド内に持つのではなく、データをスレッド外に移動して保護し、両方のスレッドからアクセスできるようにします。

以下は、あなたができることのスケッチです。

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);
  /* ... */
};

の構成は Counter がよく言われるのは モニター Wikipediaより引用(強調)。

<ブロッククオート

並行プログラミングにおいて、モニターとは、複数のスレッドで安全に使用されることを目的としたオブジェクトまたはモジュールのことです。モニタの特徴は、そのメソッドが相互排除で実行されることです。つまり、各時点で、最大でも1つのスレッドがそのメソッドを実行することができます。これは 相互排除は、データ構造を更新する並列コードに関する推論と比較して、モニターの実装に関する推論を大幅に簡素化します。 .

この具体的なケースでは、より効率的な構成は次のようになります。 QAtomicInt . これは、特殊なCPU命令を使用することでアトミック性を獲得しています。 これは低レベルのクラスであり、他のスレッド構造を実装するために使用することができます。


Edit - 完全な例

スレッドと共有状態を正しく使用することは些細なことではありません。Qtのシグナルやスロットをキュー接続や他のメッセージベースのシステムで使用することを検討するとよいでしょう。

また、Adaのような他のプログラミング言語では、スレッドとモニター(保護されたオブジェクト)をネイティブな構造体としてサポートしています。

以下は完全な動作例です。 これは単なるサンプルコードです。 QTest::qSleep を実際のコードで使用します。

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

コンパイルして実行すると、値が出力されるのがわかります、サンプル出力です。

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