使用QThreads与多个硬件设备进行通信 [英] Use QThreads to communicate with several Hardware devices

查看:121
本文介绍了使用QThreads与多个硬件设备进行通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个C ++工具,可以与多个硬件设备(相同的代码->线程函数,但有多个设备)进行通信

I wrote a C++ tool that communicate with several hardware devices (same code -> thread function, but multiple devices)

我当前的方法是使用Winapi线程机制n beginthreadex()WaitForMultipleObjects()(有效)

My current approach was to use the Winapi threading mechanismn beginthreadex() and WaitForMultipleObjects() (it works)

int vectorIndex = 0;
for(int deviceCounter=0; deviceCounter<GetNumberOfDevices(); deviceCounter++)
{                                           
    // create thread DATA object                
    testFlowVector.push_back(std::make_shared<TestFlow>(m_testResultsVector, m_logFiles));
    testFlowVector.at(vectorIndex)->SetThreadID(deviceCounter); // threadID is here the number to the device network socket


    // CREATE THREADS       
    m_threadHandle->at(deviceCounter) = (HANDLE)_beginthreadex(0, 0, TestExecution::ExecTestFlow, testFlowVector.at(vectorIndex).get(), 0, 0);

    vectorIndex++;
}           

// wait for all threads         
DWORD waitReturn = WaitForMultipleObjects(m_tpgmParam->GetNumberOfReader(), m_threadHandle->data(), true, m_tpgmParam->GetThreadTimeout()); 

静态线程功能:

unsigned int __stdcall TestExecution::ExecTestFlow(void *param)
{   
    TestFlowInterface *testFlowInterface = static_cast<TestFlowInterface*>(param);      
    testFlowInterface->run();   

    return 999;
}

线程接口:

class TestFlowInterface
{
    virtual void ExecuteTestflow() = 0;

public:
    void run() { ExecuteTestflow(); } 
    virtual ~TestFlowInterface() {} 
};

测试流程类:

class TestFlow : public TestFlowInterface
{
public:
    TestFlow(std::shared_ptr<std::vector<int>> testResults, std::shared_ptr<LogFiles> logFiles);    
    ~TestFlow();

    void ExecuteTestflow();
    // ...
};

我将Qt5用于GUI,网络通信等,并且还希望根据以下文档重做我的代码以使用QThreads:

I'm using Qt5 for the GUI, network communication and so on and want also rework my code to use QThreads based on this documentation: http://doc.qt.io/qt-5/qthread.html

有2个解决方案

  • 子类QThread
  • 使用moveToThread()(推荐)
  • subclass QThread
  • use moveToThread() (recommended)

我都尝试过,但无法更改.

I tried both but I was not able to change it.

------

TestFlow类

class TestFlow : public QObject
{
    Q_OBJECT

public:
    TestFlow(std::shared_ptr<LogFiles> logFiles, QObjects *parent=0);   
    ~TestFlow();

    void ExecuteTestflow();
    // ...

private:
    QMutex m_mutex;
    std::vector<int> m_testResults;

signals:
    void ResultReady(const std::vector<int> &result);

public slots:
    void DoWork();

};

void TestFlow::DoWork()
{
    QMutexLocker mutexLocker(m_mutex);
    ExecuteTestflow();

    emit ResultReady(m_testResults);
}

测试执行:

class TestExecution : public QObject
{
    Q_OBJECT

public:
    TestExecution()
    {
        m_workerThread = new QThread();
    }
    ~TestExecution();

private:
    QThread *m_workerThread;

public slots:
    void HandleTestResult(const std::vector<int> &result)
    {
        // do something with result
    }

};

void TestExecution::StartTest()
{
    for(int deviceCounter=0; deviceCounter<GetNumberOfDevices(); deviceCounter++)
    {
        TestFlow *testFlow = new TestFlow();
        testFlow->SetThreadID(deviceCounter);

        connect(testFlow, &TestFlow::ResultReady, this, &TestExecution::HandleTestResult);
        connect(m_workerThread, &QThread::started, testFlow, &TestFlow::DoWork);
        testFlow->moveToThread(m_workerThread);

        m_workerThread->start();
        m_workerThread->wait(m_tpgmParam->GetThreadTimeout());
    }
}

有人可以帮我吗?

推荐答案

除非您想更改QThread用作线程util/class的方式,然后不要对其进行子类化,请使用moveToThread.以下是有关使用moveToThread()的一些注意事项:

Unless you want to change the way in which QThread works as a threading util/class then don't sub-class it, use moveToThread. Here are some notes on using moveToThread():

QThread注释:

重要的是要了解QThreads的工作方式.使用QThreads的一般过程是:

It is important to understand how QThreads work. The general procedure to using the QThreads is:

  • 使对象进入线程,不分配父对象
  • 创建线程
  • 使用obj-> moveToThread(thread)将对象移动到广告中
  • 将信号连接到对象中的插槽,该插槽将使对象成员不真实(如果需要)
  • 启动线程:thread-> start()

现在,一旦对象接收到实例化其成员的信号,它们将成为 在线程中实例化.

Now once the object receives the signal to instantiate its members they will be instantiated within the thread.

注意:如果您直接从线程外部(或从另一个线程)调用使对象成员实例化的对象方法,则这些对象实际上是在线程外部创建的,您可能会得到警告说类似: 无法从另一个线程启动计时器" 即成员函数不是线程安全的.

Note: if you call an object method directly from outside the thread (or from another thread) which instatiates object members, then these objects will infact be created from outside the thread, and you may get warnings saying things like: "timers cannot be started from another thread" i.e. member functions are not thread-safe.

// Good example:
MyObj myObj = new MyObj(0); // 0 = no parent
QThread* thread = new QThread;
myObj->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), myObj, SLOT(run()));
thread->start();

// Bad example:
MyObj myObj = new MyObj(0); // 0 = no parent
QThread* thread = new QThread;
myObj->moveToThread(thread);
thread->start();
myObj->run(); //BAD - anything run() instantiates will be in 'this' thread - i.e. never call functions to this class directly once it has been moved to the other thread.

对于您的代码,您只需要创建一个类/对象即可在其中运行线程/硬件通信代码并实现run()插槽函数.然后,您可以使用上面的示例进行设置.

For your code you just need to create a class/object in which to run your thread/hardware communication code and implement the run() slot function. Then you can use the example above to set it up.

确保您的工人"类是QOBject类(如果您在Qt Creator向导下创建该类,请确保从QObject添加继承,Qt可以为您做到这一点).您需要这样做,以便可以在类之间使用插槽/信号接口.

Make sure your "worker" class is a QOBject class (Qt can do this for you if you create the class under the Qt Creator wizard make sure you add inherits from QObject). You need this so that you can use slots / signals interface between your classes.

编辑,因为代码已发布.

删除m_workerThread->wait(m_tpgmParam->GetThreadTimeout());,因为这阻塞了事件队列,因此您对工作线程的答复没有通过.

Remove the m_workerThread->wait(m_tpgmParam->GetThreadTimeout()); as this is blocking the event queue and therefore your reply form the worker thread is not getting through.

您需要转移到更多事件驱动的设计,因为像等到这里"这样的事情在qt插槽/信号旁边并不是很好的设计(即,它不是您打算如何使用它的方法).

You will need to move to a more event driven design since doing somthing like a "wait here until" is not great design alongside qt slots/signals (i.e. its not how you are meant to use it).

但是,如果您确实想等待线程结束,则必须确保您的dowork()函数结束线程.我认为您需要使用QThread::quit()函数来结束dowork()函数中的线程.

But if you did want to wait for the thread to end, then you will have to make sure that your dowork() function ends the thread. I think you need to use the QThread::quit() function to end the thread from your dowork() function.

链接到有用的线程指南

请参阅这里

在这里看看工作线程如何发出完成信号,该信号已连接到QThread :: quit()插槽.这是结束您要执行的操作的最佳方法,需要等待您的思考,以了解您等待的原因.

Take a look here at how the worker thread emits the signal finished which is connected to QThread::quit() slot. This is the best way to end the thread for what you are trying to do, it will need a bit of thought from your side on the reason why you are waiting.

示例代码

signals:
    void ResultReady(const std::vector<int> &result);
    void quitThread(); // <------------- New signal

public slots:
    void DoWork();

};

void TestFlow::DoWork()
{
    QMutexLocker mutexLocker(m_mutex);
    ExecuteTestflow();

    // V------ Note this signal will NOT get processed until your wait function is finished! and it won't finish until the thread finishes (or your timeout occurs)...
    emit ResultReady(m_testResults);
    emit quitThread(); // <------------- Signal the thread can quit
}

-

void TestExecution::StartTest()
{
    for(int deviceCounter=0; deviceCounter<GetNumberOfDevices(); deviceCounter++)
    {
        TestFlow *testFlow = new TestFlow();
        testFlow->SetThreadID(deviceCounter);

        connect(testFlow, &TestFlow::ResultReady, this, &TestExecution::HandleTestResult);
        connect(m_workerThread, &QThread::started, testFlow, &TestFlow::DoWork);
        // V------------- Connect the quitThread signal to the quit slot of the thread
        //to end the thread once worker is signals it is done.
        connect(testFlow, &QThread::quitThread, m_workerThread, &QThread::quit);
        testFlow->moveToThread(m_workerThread);

        m_workerThread->start();

        /* V------------- 
           This should now get un-blocked once the thread ends since the
           quitThread signal goes directly to the thread and therefore is
           not blocked by this "wait" which IS blocking THIS thread from
           processing incoming signals. */
        m_workerThread->wait(m_tpgmParam->GetThreadTimeout());
    }
}

这篇关于使用QThreads与多个硬件设备进行通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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