【问题标题】:Multithreading advice多线程建议
【发布时间】:2016-03-13 12:30:53
【问题描述】:

我正在开发一个应用程序,主要目标是从图像采集卡中抓取图像,进行一些处理,然后在 GUI 上显示图像。 图像采集卡连接到 PCIe。我正在使用图像采集卡 SDK。 图像流非常慢 10 到 100 张图像/秒 我来这里是为了对我的代码以及如何优化它有一些建议。 首先,我的 run() 函数来自从 Qthread 继承的类 我抓取一张图像并将其放在缓冲区 queuecv:: Mat>.

void ImageIn::run(){
        _cam->allocMemory();
        _cam->startAquisition();
        _runningThread = true;

        while(_runningThread)
        {
             Mat image(_cam.getSizeX(), _cam.getSizeY(), CV_16U, _cam->getImageDMA0());

             _ctrl->getMutexIn()->lock(); // Lock BufferIn
             _ctrl->getBufferIn()->push(image); // store Image in BufferIn
             _ctrl->getMutexIn()->unlock(); // Unlock bufferIn
        }

}

图像存储在缓冲区中,然后处理线程做一些工作......

void ImageProcessing::run(){
while(_runningThread){
if (_ctrl->getMutexIn()->tryLock()){
    while(!_ctrl->getBufferIn()->empty()){
        _ctrl->getBufferIn()->front().convertTo(tempConvert, CV_32F);
        _bufferLocalIn.push(tempConvert);
        _ctrl->getBufferIn()->pop();
    }
    _ctrl->getMutexIn()->unlock();
}

// Do some processing and put image and a buffer for GUI
}
}

所以,我有一些问题: - 由于阻塞功能,线程 1 获取图像,因此 CPU 消耗很低,但线程 2 连续运行并消耗大量 CPU 重新评估我能做些什么来解决这个问题? - 这是正确的编码方式吗?


所以我尝试了:

QThread* thread = new QThread;
ImageWriter* worker = new ImageWriter();
worker->moveToThread(thread);

QTimer* timer = new QTimer();
int msec = 100;
timer->setInterval(msec);

QObject::connect(thread, SIGNAL(started()), worker, SLOT(process()));
QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
QObject::connect(timer, SIGNAL(timeout()), thread, SLOT(start()));
timer->start();

还好吗?

【问题讨论】:

  • 了解条件等待。您可以让第二个线程等待,直到第一个线程捕获到要处理的新图像。然后它将继续处理,直到输入图像列表为空并退回到条件等待。我有一个问题:阻止功能来自您的图像采集卡 SDK,以等待有新图像可用后再尝试抓取?
  • 谢谢,我会阅读有关条件等待的信息并尝试一下。是的,_cam->getImageDMA0() 函数从图像采集卡 SDK 调用了一个阻塞函数。此阻塞功能等待新图像。

标签: c++ multithreading qt opencv


【解决方案1】:

由于Qt是一个事件驱动的框架,每个线程都有一个事件队列,它接收事件并将它们发送给各种对象来接收。

如果线程中的任何代码段本质上都有一个 while(1) 循环,那么事件传播就不会发生,这就是你在两个线程中所做的事情

while(_runningThread)

在无限循环中饿死事件处理是过度消耗 CPU 的原因。

可以通过在无限循环中调用QApplication::processEvents 来让Qt 处理事件,但这并不理想。

更好的方法是使用QTimer 对处理进行时间切片,并让事件传播自然发生。这需要在保存处理状态然后返回事件循环之前决定处理可能发生多长时间。计时器的滴答声将调用您的处理函数,然后可以恢复状态并继续。

如果您创建从 QObject 派生的处理类并将其移至 QThread,而不是直接从 QThread 本身继承,则此方法将更容易。 How to Really Truly Use QThread 上有一篇很棒的文章,可以用作模板说明如何执行此操作。

最后,考虑您可以有多个QThread,以及多个QObjectQThread 上运行。作为一般规则,如果线程数超过可用的处理器内核数,您将不会受益。

如果您知道目标机器是四核,您可以创建 3 个额外的 QThreads(总共 4 个,包括主线程),创建多个处理对象并将它们移动到不同的线程以提供最佳处理。

【讨论】:

  • 我也会试试这个解决方案。 QwaitCondition 比使用 moveToThread 更好吗?
  • 这是在比较两个完全不同的东西。正如QWaitCondition 的文档所述,QWaitCondition 类提供了用于同步线程的条件变量,而 moveToThread 将对象移动到线程,以便在该线程上进行处理。
  • 好的,我会看到的。所以,我有一个问题,如果图像处理速度太快,我会调用太多的处理函数(移动到线程)这是不安全的吗?
  • 不确定我是否理解您的问题。您设置将处理所有图像的对象,然后将其移动到新线程......您只需调用一次 moveToThread。如果您收到图像的速度比处理图像的速度快,则必须将图像排队,直到可以处理它们。
  • 我已经读过了。我在 1 个月前找到了它(非常好的文章)
猜你喜欢
  • 2017-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多