Qt多线程通信 [英] Qt Multithread communications

查看:372
本文介绍了Qt多线程通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是C ++和Qt的新手,我在实现良好且不太复杂的多线程通信环境方面遇到一些麻烦。

I am new to C++ and Qt and I am having some trouble in achieving a good and not overcomplicated multithread communication environment.

基本上我有3个线程,一个用于 GUI ,另一个用于处理由 device 通过USB连接到PC,另一个将处理由设备控制 设备 GUI 可更改其状态。所以基本上有3个线程: GUI 设备控制

Basically I have 3 threads, one for the GUI, another for handling updates sent by a device connected to the PC by USB, and another that will process the information acquired by the device and control the device and the GUI to change their state. So basically 3 threads: GUI, device and control.

我的拳头方法是让设备使用USB发送的信息填充其私人成员,并且有一些 get()方法转换这个数据并返回它(使用互斥体来确保数据仍然有效)。问题是控制调用设备中的 get()方法,它不返回任何新的东西(我期待的方法甚至永远不会返回,因为线程被锁定在另一个方法,但他们做返回和没有新的信息,也没有断点被触发在这些 get()方法)。

My fist approach was to have device populate its private members with the information sent by USB and have some get() methods that convert this data and return it (using mutexes to assure the data was still valid). The problem is when control call the get() methods in device, it doesnt return anything new (I was expecting the methods to even never return since the thread is locked in another method, but they do return and with no new information, and also no breakpoints are triggered inside those get() methods).

Qt做交互线程通信的通常方法是使用信号和插槽,槽是当一个线程正在处理并且它有一个槽,如果发送一些信号,这个槽将永远不会被执行。即使我可以设法使用信号和插槽触发新的数据更新恐怕会有很多的信号发送,因为设备更新非常快,也有很多数据类型和使用QAtomicInt将不会有用的许多他们所以我一般的问题是什么是使线程共享数据,仍然继续运行无限的过程循环的最好方法?

The usual way Qt does inter thread communications is by using Signal and Slots, but the problem with Signal and Slots is that when one thread is processing and it has a Slot, this Slot will never be executed if some Signal is sent. Even if I could manage to use Signal and Slots to trigger new data updates I am afraid there will be lots of Signals being sent since the device updates very fast, also I have lots of data types and using QAtomicInt will not be useful for many of them so my general question is which is the best way to make the threads share data and still keep running an infinite process loop?

我的目标的例子是有类似的:

A good example of my goal is having something like:

控制线程:

while(true){
    angle = device.getAngle(); //device is a member of control object and is running in a separate thread
    doCalculations(angle);
}

设备主题:

void process(){
while(true)
    usbRead(data, size_of_data);
}

short getAngle(){
    return (data[0] << 8 | data[1]);
}



我不在这个例子中放置互斥体等等,只是一个基本功能

I am not placing in this example the mutexes and etc, just a basic functionality to be expected.

根据请求,我如何开始我的主题:

As requested here is how I start my threads:

test::test(QWidget *parent) : QMainWindow(parent) , cvControl(device, 0)
{ 
    //ui setup

    connect(&device, SIGNAL(deviceConnected(bool)), this, SLOT(updateStatusConnection(bool)));

    device.moveToThread(&deviceThread);
    cvControl.moveToThread(&controlThread);

    connect(&deviceThread, SIGNAL(started(void)), &device, SLOT(process(void)));   
    connect(&device, SIGNAL(deviceFinished(void)), &deviceThread, SLOT(quit(void)));
    connect(&cvControl, SIGNAL(controlFinished(void)), &controlThread, SLOT(quit(void)));
    connect(&deviceThread, SIGNAL(finished(void)), &device, SLOT(deleteLater(void)));
    connect(&controlThread, SIGNAL(finished(void)), &cvControl, SLOT(deleteLater(void)));

    connect(this, SIGNAL(startControlProcess(void)), &cvControl, SLOT(process(void)));

    deviceThread.start();
    controlThread.start();
}

void test::on_btnRun_clicked()
{
    if(ui.btnRun->text() == "Run")
    {
        ui.btnRun->setText(QString("Stop"));
        disbleControls();
        emit startControlProcess();
    }
    else
    {
        ui.btnRun->setText(QString("Run"));
        enableControls();
        cvControl.abort.store(1);
    }
}


推荐答案

是处理这个问题的一种以上的方法:

There are more than one approach for dealing with this issue:

1)手动睡眠和自己在某些时间醒来,以检查是否有改变。这将被术语称为轮询。

1) Manual sleep and waking up at certain periods yourself to check if something is changed. This would be called polling by the jargon.

2)使用事件循环来处理事件,如信号和槽。

2) Use an event loop for your thread to process the events like signals and slots.

我建议后者,因为前者可能有缺陷,字面上不能在睡觉时做任何事情,你可能会错了。更重要的是,你也会失去伟大的信号和槽机制,突然,你的代码会变得有点多了必要的耦合。

I would suggest the latter because the former may have the defect of literally not being able to do anything while sleeping and you may get it wrong. More importantly, you would also lose the great signal and slot mechanism all of a sudden, and your code would become somewhat more coupled than necessary.

,你需要确保有适当的Qt事件循环执行,这由更新版本的 QThread 保证。也就是说,请阅读以下文档,因为我认为这是有用的注意:

As for doing the latter correctly, you would need to make sure to have the proper Qt event loop execution in place which is guaranteed by the later versions of QThread. That being said, please read the following documentation as I think it is useful to be aware of:


int QThread :: exec()[protected]

进入事件循环并等待直到exit()被调用,返回传递给exit()的值。如果通过quit()调用exit(),返回的值为0。

Enters the event loop and waits until exit() is called, returning the value that was passed to exit(). The value returned is 0 if exit() is called via quit().

此函数旨在从run()内调用。有必要调用此函数来开始事件处理。

This function is meant to be called from within run(). It is necessary to call this function to start event handling.

您也可以完成一个介于第三个解决方案之间,通过混合上述两种方法,即:调用下面的方法以显式地确保所有事件都被处理。这将是一个半(a)同步方式(取决于你如何看待它),因为你需要这样做,当从睡眠中轮询,而不是手动处理轮询,你可以使用这种方便方法。

You could also accomplish an in-between third solution as well, eventually, by mixing the two aforementioned approaches, namely: call the method below to explicitly make sure all the events are getting processed. It would be a semi-(a)sync way (depending on how you look at it) since you would need to do that when waking up from the sleeping for polling, but rather than dealing with the polling manually, you could use this convenience method.


void QCoreApplication :: processEvents(QEventLoop :: ProcessEventsFlags flags = QEventLoop :: AllEvents)[static]

处理所有待处理的事件

当程序忙于执行长操作时,您可以偶尔调用此函数。复制文件)。

You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file).

如果您正在运行一个本地循环,而不连续调用此函数,则不会处理DeferredDelete事件。这可以影响小部件的行为,例如QToolTip,它依赖DeferredDelete事件来正常工作。另一种方法是在该本地循环中调用sendPostedEvents()。

In the event that you are running a local loop which calls this function continuously, without an event loop, the DeferredDelete events will not be processed. This can affect the behaviour of widgets, e.g. QToolTip, that rely on DeferredDelete events to function properly. An alternative would be to call sendPostedEvents() from within that local loop.

调用此函数只处理调用线程的事件。

Calling this function processes events only for the calling thread.

这篇关于Qt多线程通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆