C++中的多线程实现

Posted

技术标签:

【中文标题】C++中的多线程实现【英文标题】:Multithreading Implementation in C++ 【发布时间】:2019-08-05 08:57:56 【问题描述】:

我是在 C++ 中使用多线程的初学者,如果您能给我一些建议,我将不胜感激。

我有一个从视频流中接收前一帧和当前帧的函数(我们称这个函数为readFrames())。该函数的任务是计算运动估计。

调用readFrames() 时的想法是:

    将前一帧和当前帧存储在缓冲区中。 我想计算缓冲区中每对帧之间的运动值,但不会阻塞函数readFrames(),因为在计算该值时可以接收更多帧。我想我必须编写一个函数computeMotionValue(),每次我想执行它时,创建一个新线程并启动它。这个函数应该返回一些float motionValue。 每当任何线程返回的motionValue 超过阈值时,我想 +1 一个公共 int 变量,我们称之为nValidMotion

我的问题是我不知道在访问motionValuenValidMotion 时如何“同步”线程。

你能用一些伪代码向我解释一下我该怎么做吗?

【问题讨论】:

你可以有一个接收帧队列和一个线程。如您所述计算运动值,您可以弹出 2 个最后输入的帧值和一个函数,这 2 个通过互斥锁和条件变量同步 你可以做nValidMotion atomic,任何对它的访问都会自动同步。 您正在寻找的解决方案是“生产者-消费者”问题的变体:en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem 在您的情况下,生产者线程读取帧并将它们放入处理队列。该队列与消费者线程共享。两个线程都需要一种方法来同步它们对队列的访问,以防止一个线程从另一个线程下面拉出地毯。我的第一个快速搜索出现了这个例子,看起来这将是一个足够好的起点来了解线程:gist.github.com/dpressel/de9ea7603fa3f20b55bf 【参考方案1】:

每次我想执行它时,创建一个新线程并启动它

这通常是个坏主意。线程通常相当重,生成线程通常比将消息传递到现有线程池要慢。

无论如何,如果你落后了,你最终会得到比处理器内核更多的线程,然后由于上下文切换开销和内存压力,你会落后得更远。最终创建新线程会失败。

我的问题是我不知道在访问motionValue 和nValidMotion 时如何“同步”线程。

访问共享资源的同步通常使用std::mutex 处理(mutex 的意思是“互斥”,因为一次只有一个线程可以持有锁)。

如果您需要等待另一个线程执行某项操作,请使用std::condition_variable 等待/发出信号。您正在等待/发出某些共享资源状态更改的信号,因此您也需要一个互斥锁。

这种处理的通常建议是每个可用内核最多有一个线程,所有线程都服务于一个线程池。线程池有一个工作队列(受互斥体保护,并带有由 condvar 发出的空->非空转换信号)。

为了组合结果,您可以拥有一个受互斥体保护的全局计数器(但这对于单个整数来说相对较重),或者您可以将每个任务添加到添加到线程池通过promise/future机制返回一个布尔值,或者你可以让你的计数器atomic

【讨论】:

您可以尝试使用 std::async 而不是编写自己的线程池,顺便说一句 - 老实说,我不知道执行的质量如何,但可能值得一试。 【参考方案2】:

这是您可以使用的示例伪代码:

// Following thread awaits notification from worker threads, detecting motion
nValidMotion_woker_Thread()

    while(true)  message_recieve(msg_q); ++nValidMotion; 



// Worker thread, computing motion on 2 frames; if motion detected, notify uysing message Q to nValidMotion_woker_Thread
WorkerThread(frame1 ,frame2)

    x =  computeMotionValue(frame1 ,frame2);

    if x > THRESHOLD
    msg_q.send();


// main thread
main_thread()

    // 1. create new message Q for inter-thread communication
    msg_q = new msg_q();

    // start listening thread
    Thread a = new nValidMotion_woker_Thread();
    a.start();

    while(true)
    
        // collect 2 frames
        frame1 =  readFrames();
        frame2 =  readFrames();

        // start workre thread
        Thread b = new WorkerThread(frame1 ,frame2);
        b.start();      
    

【讨论】:

以上是关于C++中的多线程实现的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C++ 中的多线程会降低性能

c++ 中的多线程线程安全动画建议

C++中的多线程,只检查信号量是不是被锁定

C++中的多线程矩阵乘法

PySide 中的多线程提升 Python C++ 代码

C ++中的多线程文件散列[关闭]