2014-02-07 222 views
1

我嘗試實現這一點:當應用程序啓動時,我需要創建多個線程,使用相同的QDialog窗口從用戶獲取消息。當線程啓動時,它會要求用戶輸入,如果按下OK按鈕,它會將消息打印到控制檯。我找不到爲什麼,但我只有一次對話框窗口,然後打印我的一條消息到控制檯和應用程序完成。線程只執行一次

下面是如何描述的對話窗口:

#include <QtWidgets> 

class MyDialog : public QDialog 
{ 
    Q_OBJECT 
public: 
    QWaitCondition* condition; 

    explicit MyDialog(QWidget *parent = 0); 

signals: 
    void got_message(QString); 
public slots: 
    void show_message_input(); 
    void show_message(); 
private: 
    QLabel* message_label; 
    QVBoxLayout* vbox; 
    QHBoxLayout* hbox; 
    QLineEdit* message_input; 
    QDialogButtonBox* dialog_buttons; 

}; 

MyDialog::MyDialog(QWidget *parent) : QDialog(parent) 
{ 
    setModal(true); 

    message_label = new QLabel("Message"); 
    message_input = new QLineEdit(); 

    dialog_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 

    hbox = new QHBoxLayout(); 
    hbox->addWidget(message_label); 
    hbox->addWidget(message_input); 

    vbox = new QVBoxLayout(); 
    vbox->addLayout(hbox); 
    vbox->addWidget(dialog_buttons); 

    setLayout(vbox); 

    connect(dialog_buttons, SIGNAL(accepted()), this, SLOT(accept())); 
    connect(dialog_buttons, SIGNAL(rejected()), this, SLOT(reject())); 

    condition = new QWaitCondition(); 
} 

void MyDialog::show_message_input() 
{ 
    int result = this->exec(); 
    if (result == QDialog::Accepted) 
    { 
     emit got_message(message_input->text()); 
     condition->wakeAll(); 
    } 
} 

這裏是MyThread的類:

class MyThread : public QThread 
{ 
    Q_OBJECT 
public: 
    explicit MyThread(int id, MyDialog* window, QObject *parent = 0); 

signals: 
    void show_input(); 
public slots: 
    void print_message(QString); 
private: 
    static QMutex mutex; 
    static QMutex mutex2; 
    MyDialog* window; 
    int id; 
    void run(); 
    void get_captcha_value(); 
}; 

QMutex MyThread::mutex; 
QMutex MyThread::mutex2; 

MyThread::MyThread(int id, MyDialog* window, QObject *parent) : 
    QThread(parent) 
{ 
    this->id = id; 
    this->window = window; 

    connect(this, SIGNAL(show_input()), this->window, SLOT(show_message_input())); 
} 

void MyThread::get_captcha_value() 
{ 
    QMutexLocker lock(&mutex); 
    connect(this->window, SIGNAL(got_message(QString)), SLOT(print_message(QString))); 
    emit show_input(); 
    mutex2.lock(); 
    window->condition->wait(&mutex2); 
    mutex2.unlock(); 
} 

void MyThread::run() 
{ 
    mutex.lock(); 
    qDebug() << "Starting thread " << id; 
    mutex.unlock(); 
    get_captcha_value(); 
    mutex.lock(); 
    qDebug() << "Finishing thread " << id; 
    mutex.unlock(); 
} 

void MyThread::print_message(QString message) 
{ 
    qDebug() << message; 
    QObject::disconnect(this, SLOT(print_message(QString))); 
} 

而且main功能:

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    MyDialog* window = new MyDialog(); 
    QList<MyThread*> threads; 
    for(int i = 0; i < 5; i++) 
    { 
     MyThread* thread = new MyThread(i, window); 
     threads << thread; 
     thread->start(); 
    } 
    return a.exec(); 
} 
+2

如果你打算使用插槽,子類'QThread'不是一個好主意。在[docs](https://qt-project.org/doc/qt-5.0/qtcore/qthread.html#details)中說明:*重要的是要記住QThread對象通常位於它所在的線程中創建,而不是在它管理的線程中。這個經常被忽視的細節意味着QThread的插槽將在其主線程的上下文中執行,而不是在其正在管理的線程的上下文中執行。由於這個原因,在QThread子類中實現新的插槽是很容易出錯和不鼓勵的。* – thuga

回答

0

你的第一個問題是,你從QThread繼承。除非你想重寫Qt處理線程的方式,you're doing it wrong!

您需要做的是從QObject繼承並將實例移動到新線程的類。繼承QThread的主要問題是它可能會導致線程關聯(運行對象的線程)的混淆。

另外,創建比處理器內核更多的線程只是浪費資源。

我建議你read this article關於如何使用Qt線程並停止從QThread繼承。

最後,QMutex的使用是保護多個線程同時訪問相同的數據。你應該能夠在你所顯示的代碼中刪除它們。用一個線程中的數據發送信號以便被另一個線程中的一個槽接收是Qt中的首選方法。

+1

創建比處理器核心更多的CPU綁定線程將浪費資源。 –

+0

@MartinJames,當然,但在這種情況下,它被認爲是CPU綁定的,因爲代碼中的所有線程都被創建並運行。感謝澄清。 – TheDarkKnight

+0

如果我寫網絡應用程序,它不會是cpu-bound,對吧? –