【问题标题】:Thread executed only once线程只执行一次
【发布时间】:2014-03-04 21:47:51
【问题描述】:

我尝试实现这一点:当应用程序启动时,我需要创建多个线程,这些线程将使用同一个 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();
}

【问题讨论】:

  • 如果您要使用插槽,子类化QThread 不是一个好主意。在docs 中声明:重要的是要记住,QThread 对象通常存在于创建它的线程中,而不是它管理的线程中。这个经常被忽视的细节意味着 QThread 的槽将在其主线程的上下文中执行,而不是在它所管理的线程的上下文中。因此,在 QThread 子类中实现新插槽容易出错且不鼓励。

标签: c++ multithreading qt qt5


【解决方案1】:

您遇到的第一个问题是您从 QThread 继承。除非你想重写 Qt 如何处理线程,you're doing it wrong!

您需要做的是拥有一个继承自 QObject 的类并将实例移动到新线程。继承 QThread 的主要问题是它可能会导致混淆线程亲和性(对象在哪个线程上运行)。

此外,创建比处理器内核更多的线程只是浪费资源。

我建议您read this article 了解如何使用 Qt 线程并停止从 QThread 继承。

最后,使用 QMutex 是为了保护多个线程同时访问相同的数据。您应该能够在显示的代码中删除所有这些。 Qt 中的首选方法是使用来自一个线程的数据发出信号以由另一个线程上的插槽接收。

【讨论】:

  • 创建比处理器内核更多的 CPU 绑定线程将浪费资源。
  • @MartinJames,当然可以,但在这种情况下假定它受 CPU 限制,因为代码中的所有线程都已创建并运行。感谢您的澄清。
  • 如果我写网络应用程序,它不会是cpu限制的,对吧?
  • @DmitryMikhaylov,受 CPU 限制的线程是其执行速度与 CPU 速度相关的线程。相比之下,IO 绑定的东西与 CPU 无关。例如,等待用户输入,线程大部分时间都在等待用户。
  • 你最后的建议是什么意思?我有一个窗口,我不希望线程同时访问它。这就是我使用互斥锁的原因。那有什么问题?尝试从文章中应用这个东西,现在它几乎相同但是线程没有从窗口获得任何信号。
猜你喜欢
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 2017-09-27
  • 1970-01-01
  • 2018-11-17
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多