C++中的多线程实现
Posted
技术标签:
【中文标题】C++中的多线程实现【英文标题】:Multithreading Implementation in C++ 【发布时间】:2019-08-05 08:57:56 【问题描述】:我是在 C++ 中使用多线程的初学者,如果您能给我一些建议,我将不胜感激。
我有一个从视频流中接收前一帧和当前帧的函数(我们称这个函数为readFrames()
)。该函数的任务是计算运动估计。
调用readFrames()
时的想法是:
-
将前一帧和当前帧存储在缓冲区中。
我想计算缓冲区中每对帧之间的运动值,但不会阻塞函数
readFrames()
,因为在计算该值时可以接收更多帧。我想我必须编写一个函数computeMotionValue()
,每次我想执行它时,创建一个新线程并启动它。这个函数应该返回一些float motionValue
。
每当任何线程返回的motionValue
超过阈值时,我想 +1 一个公共 int 变量,我们称之为nValidMotion
。
我的问题是我不知道在访问motionValue
和nValidMotion
时如何“同步”线程。
你能用一些伪代码向我解释一下我该怎么做吗?
【问题讨论】:
你可以有一个接收帧队列和一个线程。如您所述计算运动值,您可以弹出 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++中的多线程实现的主要内容,如果未能解决你的问题,请参考以下文章