2014-02-07 4 views
1

Я пытаюсь реализовать это: при запуске приложения мне нужно создать несколько потоков, которые будут использовать одно и то же окно QDialog для получения сообщений от пользователя. Когда поток запущен, он запрашивает у пользователя ввод, а при нажатии кнопки «ОК» он выводит сообщение на консоль. Я не могу понять, почему, но я получаю диалоговое окно только один раз, и после этого он печатает мое одно сообщение для завершения консоли и приложений.Thread, выполняемый только один раз

Вот как я описываю диалоговое окно:

#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

Создание большего количества потоков, связанных с процессором, чем процессорные ядра, будет пустой тратой ресурсов. –

+0

@MartinJames, ну, конечно, но предполагается, что в этом случае он связан с ЦП, поскольку все потоки в коде создаются и запускаются. Спасибо за разъяснения. – TheDarkKnight

+0

В случае, если я напишу сетевое приложение, оно не будет ограничено cpu, не так ли? –

Смежные вопросы