C++ 我可以将QObject的两个子类移动到同一个QThread吗?
我有两个子类C++ 我可以将QObject的两个子类移动到同一个QThread吗?,c++,multithreading,qt,qthread,C++,Multithreading,Qt,Qthread,我有两个子类QObject: class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = 0); signals: public slots: void process(); }; 及 我将工作线程和控制器移动到相同的QThread。我想通过ThreadController和正在工作的工作人员来控制线程(进入睡眠或醒来),现在这个想法不起作用了,工作人员可以完
QObject
:
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
signals:
public slots:
void process();
};
及
我将工作线程和控制器移动到相同的
QThread
。我想通过ThreadController
和正在工作的工作人员来控制线程(进入睡眠或醒来),现在这个想法不起作用了,工作人员可以完成进程,但控制器不能工作,我不知道我的代码出了什么问题。谢谢@thuga是的,正如你所说的。Worker::process是一个无限循环,如下所示:
void Worker::process(){
int a=(int)QThread::currentThreadId();
emit sendThreadId(a);
int b=0;
while (b<1000000) {
b++;
emit processResult(b);
QThread::msleep(1);// signal emit too quickly will block the main thread,
//so i just let the loop slow down
}
}
是的,直接连接让它工作。谢谢!我还有一些问题:当QThread使用QWaitCondition::wait()时,它会停止其中的事件循环吗?那么发送到线程的任何信号都将不再被处理
我想在我的程序中重用QThread。当工作线程完成其工作时,将向控制器发送一个信号,控制器将执行sleep()函数。下次数据到来时,控制器将唤醒()线程,工作线程将再次工作。有其他解决方案适合这种情况吗?重用QThread或删除它并重新创建它(哪种性能损失更大)?@thuga我需要workerthread中的信号和插槽。但是QtConcurrent::run无法提供这样的机制。您应该知道,我们不必在无事可做的情况下让线程休眠。在你的帮助下,我刚刚完成了这项工作。虽然我的解决方案不好,但我发布了所有代码,如下所示: 从事繁重工作的工人阶级
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
signals:
void processResult(int);
void sendThreadId(int);
public slots:
void process();
};
void Worker::process(){
QEventLoop eventloop;
int a=(int)QThread::currentThreadId();
emit sendThreadId(a);
int b=0;
while (b<1000000) {
b++;
emit processResult(b);
QThread::msleep(1);
eventloop.processEvents();
}
qDebug()<<"Worker::process() called";
qDebug()<<QThread::currentThreadId();
eventloop.exec();
}
该方案:
ThreadController::ThreadController(QObject*parent):QObject(parent){mutex=new QMutex();wc=new QWaitCondition();}Worker::process看起来像什么?那里有无限循环吗?如果是这样,则永远不会执行
ThreadController::sleep
。此外,您必须从其他线程唤醒该线程,因此ThreadController::wakeUp
将无法使用您的信号/插槽方法(除非您将其设置为直接连接)。@thuga您是否介意就QWaitCondition无法停止无限循环的原因向我提供更多建议。我在网上搜索了很长时间。但是没有用。请提供帮助或尝试给出一些实现方法。由于ThreadController::sleep()
方法是一个槽(应该是这样),并且无限循环会阻止事件循环,因此sleep
槽永远不会执行。如果在线程中使用插槽,则不应使用无限循环。如果要模拟无限循环,请使用QTimer
。现在我知道了。当工作线程执行无限循环时,它会阻塞线程的事件循环。因此,执行sleep()的信号将不会被处理,但wakeup()函数将被执行,因为我只在唤醒插槽的连接中使用了Qt::DirectConnection。DirectConnection只允许wakeup()在主线程中运行,因为唤醒信号是从主线程发出的。正确。您只需再次使用QTimer
@thuga thx替换无限循环即可。我还有另一个问题:使用QWaitCondition重用QThread是否值得?或者只是在需要时新建一个QThread。创建一个线程将消耗大量资源?你是什么意思?以何种方式重用?@thuga重用方式:当工作线程完成其工作时,它将向控制器发送一个睡眠信号,控制器将让workerthread进入睡眠状态。当新数据出现时,控制器将唤醒workerthread,工作线程将重新开始工作。这样做值得吗?或者在需要时创建一个新的QThread。
QObject::connect(&w,&MainWindow::wakeClicked,controller,&ThreadController::wakeUp,Qt::DirectConnection);
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
signals:
void processResult(int);
void sendThreadId(int);
public slots:
void process();
};
void Worker::process(){
QEventLoop eventloop;
int a=(int)QThread::currentThreadId();
emit sendThreadId(a);
int b=0;
while (b<1000000) {
b++;
emit processResult(b);
QThread::msleep(1);
eventloop.processEvents();
}
qDebug()<<"Worker::process() called";
qDebug()<<QThread::currentThreadId();
eventloop.exec();
}
class ThreadController : public QObject
{
Q_OBJECT
public:
explicit ThreadController(QObject *parent = 0);
~ThreadController();
signals:
void statusChanged(QString);
public slots:
void sleep();
void wakeUp();
private:
QMutex *mutex;
QWaitCondition *wc;
};
ThreadController::ThreadController(QObject *parent) : QObject(parent)
{
mutex=new QMutex();
wc=new QWaitCondition();
}
ThreadController::~ThreadController(){
delete mutex;
delete wc;
}
void ThreadController::sleep(){
qDebug()<<"ThreadController::sleep() called";
qDebug()<<QThread::currentThreadId();
emit statusChanged("WorkerThread sleeping");
mutex->lock();
wc->wait(mutex);
mutex->unlock();
}
void ThreadController::wakeUp(){
qDebug()<<"ThreadController::wakeUp() called";
qDebug()<<QThread::currentThreadId();
emit statusChanged("WorkerThread wakening");
mutex->lock();
wc->wakeAll();
mutex->unlock();
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void wakeClicked();
void sleepClicked();
public slots:
void setMainId(int);
void setThreadId(int);
void setThreadStatus(QString);
void setThreadCount(int);
private:
QLabel*l_mainThreadId;
QLabel*l_workerThreadId;
QLabel*l_workerThreadStatus;
QLabel*l_workerThreadCount;
QString count;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle("Threading Test");
QWidget *window=new QWidget;
QVBoxLayout *mainLayout=new QVBoxLayout;
QHBoxLayout *mainLayout1=new QHBoxLayout;
QHBoxLayout *mainLayout2=new QHBoxLayout;
QLabel*label1=new QLabel("Main Thread ID:");
l_mainThreadId=new QLabel;
int a=(int)QThread::currentThreadId();
QString idlabel=QString::number(a);
l_mainThreadId->setText(idlabel);
mainLayout1->addWidget(label1);
mainLayout1->addWidget(l_mainThreadId);
QPushButton* wakeButton=new QPushButton("WakeUp");
QPushButton*sleepButton=new QPushButton("Sleep");
mainLayout2->addWidget(wakeButton);
mainLayout2->addWidget(sleepButton);
mainLayout->addLayout(mainLayout1);
mainLayout->addLayout(mainLayout2);
QVBoxLayout *threadLayout=new QVBoxLayout;
QHBoxLayout *threadLayout1=new QHBoxLayout;
QHBoxLayout *threadLayout2=new QHBoxLayout;
QHBoxLayout *threadLayout3=new QHBoxLayout;
QLabel *label2=new QLabel("Worker Thread ID:");
l_workerThreadId=new QLabel;
threadLayout1->addWidget(label2);
threadLayout1->addWidget(l_workerThreadId);
QLabel *label3=new QLabel("Worker Thread Status:");
l_workerThreadStatus=new QLabel;
threadLayout2->addWidget(label3);
threadLayout2->addWidget(l_workerThreadStatus);
QLabel *label4=new QLabel("Counting Result:");
l_workerThreadCount=new QLabel;
threadLayout3->addWidget(label4);
threadLayout3->addWidget(l_workerThreadCount);
threadLayout->addLayout(threadLayout1);
threadLayout->addLayout(threadLayout2);
threadLayout->addLayout(threadLayout3);
QHBoxLayout *layout=new QHBoxLayout;
layout->addLayout(mainLayout);
layout->addLayout(threadLayout);
window->setLayout(layout);
setCentralWidget(window);
setThreadStatus("WorkerThread wakening");
QObject::connect(wakeButton,&QPushButton::clicked,this,&MainWindow::wakeClicked);
QObject::connect(sleepButton,&QPushButton::clicked,this,&MainWindow::sleepClicked);
}
MainWindow::~MainWindow()
{
}
void MainWindow::setMainId(int id){
QString idlabel=QString::number(id);
l_mainThreadId->setText(idlabel);
}
void MainWindow::setThreadId(int id){
QString idlabel=QString::number(id);
l_workerThreadId->setText(idlabel);
}
void MainWindow::setThreadStatus(QString s){
l_workerThreadStatus->setText(s);
}
void MainWindow::setThreadCount(int i){
count = QString::number (i) ;
l_workerThreadCount->setText(count);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
QThread* thread = new QThread;
Worker* worker = new Worker;
ThreadController*controller=new ThreadController();
controller->moveToThread(thread);
worker->moveToThread(thread);
QObject::connect(thread,&QThread::started,worker,&Worker::process); QObject::connect(worker,&Worker::processResult,&w,&MainWindow::setThreadCount);
QObject::connect(worker,&Worker::sendThreadId,&w,&MainWindow::setThreadId);
QObject::connect(&w,&MainWindow::wakeClicked,controller,&ThreadController::wakeUp,Qt::DirectConnection);
QObject::connect(&w,&MainWindow::sleepClicked,controller,&ThreadController::sleep);
QObject::connect(controller,&ThreadController::statusChanged,&w,&MainWindow::setThreadStatus);
thread->start();
return a.exec();
}