c++ - Qt 多线程通信

标签 c++ multithreading qt qthread qtcore

<分区>

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

基本上我有 3 个线程,一个用于 GUI,另一个用于处理通过 USB 连接到 PC 的 device 发送的更新,另一个将处理信息由 devicecontrol 获取 deviceGUI 来改变它们的状态。所以基本上有 3 个线程:GUIdevicecontrol

我的第一个方法是让 device 用 USB 发送的信息填充它的私有(private)成员,并有一些 get() 方法转换这些数据并返回它(使用互斥量以确保数据仍然有效)。问题是当 control 调用 device 中的 get() 方法时,它不会返回任何新内容(我原以为这些方法甚至永远不会返回因为线程被锁定在另一个方法中,但它们确实返回并且没有新信息,并且在那些 get() 方法中也没有触发断点)。

Qt通常的线程间通信方式是使用Signal和Slots,但是Signal和Slots的问题是当一个线程正在处理并且它有一个Slot时,如果发送了一些Signal,这个Slot将永远不会被执行。即使我可以设法使用 Signal 和 Slots 来触发新的数据更新,我担心会有很多信号被发送,因为设备更新非常快,而且我有很多数据类型并且使用 QAtomicInt 对许多人来说都没有用所以我的一般问题是,哪种方法是让线程共享数据并仍然继续运行无限进程循环的最佳方式?

我的目标的一个很好的例子是:

控制线程:

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]);
}

我没有在这个例子中放置互斥量等,只是预期的基本功能。

这里是我开始线程的方式:

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);
    }
}

最佳答案

处理这个问题的方法不止一种:

1) 手动 sleep 并在特定时间自己醒来以检查是否有任何变化。这在行话中称为轮询。

2) 为线程使用事件循环来处理信号和槽等事件。

我会建议后者,因为前者可能存在在 sleep 时实际上无法做任何事情的缺陷,您可能会弄错。更重要的是,您还会突然失去出色的信号和槽机制,并且您的代码会变得比必要的耦合度更高。

至于正确执行后者,您需要确保适当的 Qt 事件循环执行到位,QThread 的更高版本保证了这一点。话虽如此,请阅读以下文档,因为我认为了解这些文档很有用:

int QThread::exec() [protected]

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().

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

您最终也可以通过混合上述两种方法来完成中间的第三种解决方案,即:调用下面的方法以明确确保所有事件都得到处理。这将是一种半(a)同步方式(取决于您如何看待它),因为您需要在从 sleep 中醒来进行轮询时这样做,而不是手动处理轮询,您可以使用这种便利方法。

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

Processes all pending events for the calling thread according to the specified flags until there are no more events to process.

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

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.

关于c++ - Qt 多线程通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20830773/

相关文章:

c++ - 在 C++ 结构中处理未知类型的最佳方法是什么?

java - executorservice 以 block 的形式从数据库中读取数据并在其上运行进程

c++ - Qt:将 QCoreApplication/QNetworkAccessManager 与共享动态 C++ 库一起使用

c++ - 如何在 Qt 中制作一个恒定正确的只读模型/ View 架构?

c++ - 这种模运算安全吗?

c++ - 为通用树定义迭代器

java - 多线程 - 在线程池中安排永无休止的可运行

python - 有人可以帮助我使用 python 网络程序吗?

qt - QML:子属性的别名

c++ - 检查文件大小而不用 C++ 打开文件?