2014-02-07 225 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,对吧? –