我有一个类,它是某个设备的抽象。
class Device
{
public:
...
void Start();
void Stop();
void MsgLoop();
signals:
void sMsgArrived();
}
从GUI线程调用Start()和Stop()。 Start()开始运行MsgLoop()的新线程。它看起来像这样:
void MsgLoop()
{
forever {
if(SUCCESS == ReadMsg()) //synchronous, non-blocking
{
ProcessMsg(); //quite fast
emit sMsgArrived(); //this signal is connected with a slot in GUI thread
}
}
}
当调用Stop()时,程序应该从MsgLoop()返回并停止该线程。如何在没有子类化的情况下使用QThread实现它?
答案 0 :(得分:5)
通常,您必须决定由谁来负责管理线程。它是设备还是主窗口?或者可能是一些设备管理员在您的情况下,设备应该可以管理自己的线程,因此如果您不想将其子类化,请使用组合:
class Device : QObject
{
Q_OBJECT
public:
Device(QObject * parent = NULL);
void Start();
void Stop();
private slots:
void MsgLoop();
signals:
void sMsgArrived();
private:
QThread thread;
bool stopThread;
};
Device::Device(QObject * parent) : QObject(parent)
{
moveToThread(&thread);
connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}
void Device::Start()
{
stopThread = false;
thread.start();
}
void Device::Stop()
{
stopThread = true;
thread.wait(); // if you want synchronous stop
}
void Device::MsgLoop()
{
// your loop
while(!stopThread)
if(SUCCESS == ReadMsg())
{
ProcessMsg();
emit sMsgArrived();
}
QThread::currentThread->quit();
}
注意:只有当ReadMsg
非阻塞时,线程停止才有效。如果你以后决定切换到阻塞读取(这可能适用于大多数情况),你将不得不找到另一种方法来阻止你的线程。
答案 1 :(得分:2)
如果查看此link,您可以看到可以在单独的线程中运行方法而无需继承QThread。
然而,您所要求的是运行消息循环永远。
如果您按照给定的示例操作,则可以在不进行子类化的情况下运行循环,但QThread对象永远不会进入自己的消息循环,因为它永远不会从您的插槽返回。所以这是一个例子,但我认为这将是糟糕设计
class Device : public QObject
{
Q_OBJECT
public:
Device(QObject* parent = 0);
~Device();
public Q_SLOTS:
void MsgLoop();
};
QThread* thread = new QThread;
Device* device = new Device;
void Widget::onBtnStartClicked()
{
device->moveToThread(thread);
//This will call start method of Device
connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));
//This will start the event loop of thread
thread->start();
}
void Widget::onBtnStopClicked()
{
//Tells the thread to exit
thread->exit(0);
}
如果您想要运行永远循环,我恐怕您必须继承QThread。
答案 2 :(得分:0)