• 1359阅读
  • 4回复

[提问]QThread的迷惑 [复制链接]

上一主题 下一主题
离线kyosold622
 

只看楼主 倒序阅读 楼主  发表于: 2022-03-22
我有一个 work 任务类,准备要在线程中跑的,现在是需要有三个 work 类,在三个单独的线程去跑,但是我发现每次的第一个线程会包括后面的任务,导致第1个线程跑了三次,第二个线程跑了2次,最后一个跑一次,这是怎么回事,代码如下:
work:
  1. #ifndef WORK_H
  2. #define WORK_H
  3. #include <QObject>
  4. class Work : public QObject
  5. {
  6.     Q_OBJECT
  7. public:
  8.     explicit Work(QObject *parent = nullptr);
  9. public slots:
  10.     void startWork(QString id);
  11. signals:
  12.     void sigWorkFinished(QString id);
  13. };
  14. #endif // WORK_H

  1. #include "work.h"
  2. #include <QThread>
  3. #include <QDebug>
  4. Work::Work(QObject *parent)
  5.     : QObject{parent}
  6. {
  7. }
  8. void Work::startWork(QString id)
  9. {
  10.     qDebug() << "  Work::startWork:" << QThread::currentThread() << id << "Start ...";
  11.     int i = 0;
  12.     while (i < 5) {
  13.         i++;
  14.         QThread::sleep(1);
  15.     }
  16.     emit this->sigWorkFinished(id);
  17. }



MainWindow:
  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. #include <QThread>
  5. #include <QMap>
  6. QT_BEGIN_NAMESPACE
  7. namespace Ui { class MainWindow; }
  8. QT_END_NAMESPACE
  9. class MainWindow : public QMainWindow
  10. {
  11.     Q_OBJECT
  12. public:
  13.     MainWindow(QWidget *parent = nullptr);
  14.     ~MainWindow();
  15. private:
  16.     Ui::MainWindow *ui;
  17.     QMap<QString, QThread*> workMaps;
  18. signals:
  19.     void sigStartWork(QString id);
  20. };
  21. #endif // MAINWINDOW_H
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include "work.h"
  4. #include <QThread>
  5. #include <QDebug>
  6. MainWindow::MainWindow(QWidget *parent)
  7.     : QMainWindow(parent)
  8.     , ui(new Ui::MainWindow)
  9. {
  10.     ui->setupUi(this);
  11.     workMaps.clear();
  12.     int i=0;
  13.     while (i<3) {
  14.         QString id = QString::asprintf("pid-%1").arg(i);
  15.         QThread *thread = new QThread();
  16.         Work *work = new Work();
  17.         work->moveToThread(thread);
  18.         workMaps.insert(id, thread);
  19.         qDebug() << "Main: insert" << id << "=>" << thread;
  20.         connect(thread, &QThread::finished, work, &Work::deleteLater);
  21.         connect(this, &MainWindow::sigStartWork, work, &Work::startWork);
  22.         connect(work, &Work::sigWorkFinished, this, [=](QString id) {
  23.             qDebug() << "Main: get work" << id << "finished.";
  24.             QThread *thread = workMaps[id];
  25.             if (thread) {
  26.                 thread->quit();
  27.                 thread->wait();
  28.             }
  29.             workMaps.remove(id);
  30.             delete thread;
  31.         });
  32.         thread->start();
  33.         emit this->sigStartWork(id);
  34.         i++;
  35.     }
  36. }
  37. MainWindow::~MainWindow()
  38. {
  39.     delete ui;
  40. }

跑完的结果如下:
  1. Main: insert "pid-0" => QThread(0x7f986ad08c90)
  2. Main: insert "pid-1" => QThread(0x7f986ad15ec0)
  3. Main: insert "pid-2" => QThread(0x7f986ad0d1a0)
  4.   Work::startWork: QThread(0x7f986ad08c90) "pid-0" Start ...
  5.   Work::startWork: QThread(0x7f986ad15ec0) "pid-1" Start ...
  6.   Work::startWork: QThread(0x7f986ad0d1a0) "pid-2" Start ...
  7. Main: get work "pid-2" finished.
  8.   Work::startWork: QThread(0x7f986ad08c90) "pid-1" Start ...
  9.   Work::startWork: QThread(0x7f986ad15ec0) "pid-2" Start ...
  10. Main: get work "pid-0" finished.
  11.   Work::startWork: QThread(0x7f986ad08c90) "pid-2" Start ...
  12. Main: get work "pid-1" finished.
  13. Main: get work "pid-1" finished.
  14. Main: get work "pid-2" finished.
  15. Main: get work "pid-2" finished.
可以很明显看到线程:
    0x7f986ad08c90 跑了 pid-0, pid-1, pid-2
    0x7f986ad15ec0 跑了 pid-1, pid-2
    0x7f986ad0d1a0 跑了 pid-2

很困惑,如果我只要一个线程跑一个,怎么办???

另外,第二个问题是有关 QThreadPool 的,我的任务类继承 QRunnable,可以在里面加入flag来确定是否要退出线程,但是在 QThreadPool 里面还没开始运行(还在队列中排队的)那些,如果让它们停止或remove掉呀?





离线fsu0413

只看该作者 1楼 发表于: 2022-03-22
你emit了3个sigStartWork
第一个的时候只有0
第二个的时候有0和1,并且都响应了
第三个的时候有0、1、2,并且都响应了
离线fsu0413

只看该作者 2楼 发表于: 2022-03-22
QThreadPool我没用过
离线kyosold622

只看该作者 3楼 发表于: 2022-03-23
回 fsu0413 的帖子
fsu0413:你emit了3个sigStartWork
第一个的时候只有0
第二个的时候有0和1,并且都响应了
第三个的时候有0、1、2,并且都响应了 (2022-03-22 20:19) 

多谢,我大概明白你的意思了,看来我要在 work 里加个flag 来判断自己是否已经运行了,如果已经运行了就return;
那像这种场景,标准的写法是个什么样子呢??另外,这个 new QThread 出来的这个指针是在 thread.wait() 之后 delete thread 么?我试着这样,会报错。
离线fsu0413

只看该作者 4楼 发表于: 2022-03-25
回 kyosold622 的帖子
kyosold622:多谢,我大概明白你的意思了,看来我要在 work 里加个flag 来判断自己是否已经运行了,如果已经运行了就return;
那像这种场景,标准的写法是个什么样子呢??另外,这个 new QThread 出来的这个指针是在 thread.wait() 之后 delete thread 么?我试着这样,会报错。
 (2022-03-23 09:34) 

就3个线程创建完之后再调用sigStartWork就完事了。。。根本用不到flag
QThread::wait要返回true才能delete
快速回复
限100 字节
 
上一个 下一个