2

MyObject->moveToThread(myThread);時間がかかる通信機能にQThreadを使用しています。いくつかのシグナルとスロットは、進行状況についてGUIに投稿されたままにします。

ただし、スレッド通信中にユーザーの操作が必要な状況が発生する可能性があります。QMessageBoxはスレッド内に作成できないため、スレッドを一時停止してダイアログを表示できる信号を発することを考えていました。しかし、まず第一に、スレッドを一時停止する方法はないようです。第二に、再開時にパラメーターをスレッドに戻す方法が必要なため、この試みはおそらく失敗します。

別のアプローチは、問題のすべてのパラメーターを事前にスレッドに渡すことですが、これは常にオプションではない場合があります。

これは通常どのように行われますか?

編集

コメント#1に感謝し、私の希望を得ることができますが、スレッド内のオブジェクトからダイアログを作成する方法や、一時停止する方法などについて詳しく説明してください。

Qt4.8.1およびMSVC++2010を使用した次のサンプルコードは、次のようになります。

MyClass::MyClass created 
MainWindow::MainWindow thread started 
MyClass::start run 
ASSERT failure in QWidget: "Widgets must be created in the GUI thread.", file kernel\qwidget.cpp, line 1299

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "myclass.h"
#include <QThread>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QThread *thread = new QThread();
    MyClass* myObject = new MyClass();

    myObject->moveToThread( thread );
    connect(thread,     SIGNAL( started()),     myObject, SLOT(start()));
    connect(myObject,   SIGNAL( finished()),    thread, SLOT(quit()));
    connect(myObject,   SIGNAL( finished()),    myObject, SLOT(deleteLater()));
    connect(thread,     SIGNAL( finished()),    thread, SLOT(deleteLater()));

    thread->start();
    if( thread->isRunning() )
    {
        qDebug() << __FUNCTION__ << "thread started";
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = 0);

signals:
    void finished();

public slots:
    void start();

};

#endif // MYCLASS_H

myclass.cpp

#include "myclass.h"

#include <QMessageBox>
#include <QDebug>

MyClass::MyClass(QObject *parent) :
    QObject(parent)
{
    qDebug() << __FUNCTION__ << "created";
}

void MyClass::start()
{
    qDebug() << __FUNCTION__ << "run";

    // do stuff ...

    // get information from user (blocking)

    QMessageBox *msgBox = new QMessageBox();
    msgBox->setWindowTitle(      tr("WindowTitle") );
    msgBox->setText(             tr("Text") );
    msgBox->setInformativeText(  tr("InformativeText") );
    msgBox->setStandardButtons(  QMessageBox::Ok | QMessageBox::Cancel);
    msgBox->setDefaultButton(    QMessageBox::Ok);
    msgBox->setEscapeButton(     QMessageBox::Cancel);
    msgBox->setIcon(             QMessageBox::Information);

    int ret = msgBox->exec();

    // continue doing stuff (based on user input) ...

    switch (ret) 
    {
        case QMessageBox::Ok:
            break;

        case QMessageBox::Cancel:
            break;

        default:
            break;
    }

    // do even more stuff

    emit finished();
}
4

2 に答える 2

5

シグナル/スロット接続(QObject :: connect()の呼び出し)でQt::BlockingQueuedConnectionを使用します。

http://doc.qt.digia.com/qt/qt.html#ConnectionType-enum

これにより、UIスレッドのスロットが戻るまでスレッドがブロックされ、UIスレッドのスロットは、メッセージボックス/モーダルダイアログ/実行したいことを自由に表示できます。

ドキュメントによると、シグナルとスロットが同じスレッド上にある場合(それ自体がブロックされるため)、これによりデッドロックが発生するため、ワーカースレッドが実際にUIスレッド上にないことを確認する必要があります。

于 2012-12-18T16:42:45.287 に答える
2

今は特定のコードを提供することはできませんが、次のようにします。

  1. MyClass::start()ロックQMutex中_
  2. 信号を発しmessageBoxRequired()ます。
  3. QWaitCondition最近のミューテックスで共有を待ちます。これにより、スレッドの待機中にミューテックスもロック解除されます。
  4. MainWindow のスロットで、たとえばshowMessageBox()、メッセージ ボックスを表示します。
  5. 戻り値を のメンバーに格納しますMyClass。これを行うには、メンバーを保護するためにミューテックスを使用するセッターとゲッターを提供します。明らかにMyClass、それ自体は、それらのセッター/ゲッター自体でそのメンバーにのみアクセスする必要があります。(それについてはQMutexLockerも参照してください)。
  6. wakeOne()またはwakeAll()共有の電話をかけQWaitConditionます。
  7. 前のwait()呼び出しが返され、MyClass::start()実行が続行されます。ドキュメントを正しく理解していればQWaitCondition、ミューテックスが から戻る前に再度ロックされますwait()。これは、呼び出しの直後にミューテックスのロックを解除する必要があることを意味しますwait()
  8. クラス メンバーからメッセージ ボックスの戻り値にアクセスできます (スレッド セーフな getter を使用)。

スレッドセーフなセッター/ゲッターの実装は次のようになります。

void MyClass::setVariable( int value )
{
    QMutexLocker( &_mutex );
    _value = value;
}

int MyClass::getVariable() // Not sure if a 'const' modifier would work here
{
    QMutexLocker( &_mutex );
    return _value;
}
于 2012-12-18T16:38:01.353 に答える