C++多线程之间,线程函数启动之后,多线程依赖的启动和线程唤醒操作。
C++多线程之间,线程函数启动之后,线程间依赖的启动和唤醒操作
- 一、原理分析
- 1. 线程依赖关系
- 二、 实例分析
- 2.1 多线程启动
- 2.2 多线程模式讲解
- (1) 多线程开启与主线程唤醒
- (2)单线程需要2个锁,一个主动加锁,一个等待互斥锁释放。
- (3) 运行结果展示
一、原理分析
1. 线程依赖关系
目标检测中,为了加快速度,往往需要多线程。但是线程之间有依赖关系。然后实时控制每个线程的启动和运行。至关重要。本文讲解了,多线程函数中,线程之间有依赖关系,共享数据也有依赖。
线程ABCD。A完成后通知B,B完成业务后,通知C,C完成后,通知D,D完成后,通知A。如此循环下去。A—>B—>C—>D—>A。
我们先启动这四个线程。每个线程两个锁,一个是锁定当前的任务,让下一个任务等待,直到该线程处理完毕,再通知下一个业务线程。 另外一个锁是等待的锁,用条件变量,等上一个业务线程的通知。一旦上一个业务完成后,马上被唤醒。
对于线程B来说,需要等待A完成,等待这个锁解锁(A_B_mutex);此时,自己也要拿住对下一个线程相关联的,C的锁(B_C_mutex)。就有两个锁。主动拥有B–>C的锁,被动锁定A–>B的锁,等待A的条件变量完成,并且被通知唤醒解锁。
二、 实例分析
在我们的业务中。我们有四个内容,分别是发送信号SendCom(); 图像转换ImageConvert(); 目标检测ObjectDetection();NMS和重采样算法NMSResample()。
他们之间的内容,分别有相互共享的数据。且每一步,都需要依赖上一步的数据,以及等待上一步完成。
比如,目标检测线程,需要图像格式转换线程完毕,才能进行图像的检测。NMS重采样线程,需要对目标检测结果(目标检测线程完成),进行综合分析,完成之后,将目标的位置信号发送给SendCom线程,进行采集信号发送。他们之间形成了闭环,需要由某个线程,主动启动,才能打通依赖关系线程的开启。
因此,我们在主线程中,主动建立了一个锁,叫做主函数和NMS重采样之间的锁。通过这个锁,我们从主线程唤醒多线程中的NMSResample()线程,从而开启流水处理的多线程间相互依赖方式。
如下代码中:main_scan_mutex 来开启这个主线程多多线程的唤醒。
2.1 多线程启动
// MultiThreadSimulation.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <time.h>
#include <thread>
#include <condition_variable>using namespace std;/* condition lock, and mutex for thread controlling. */
mutex send_cvt_mutex,cvt_detect_mutex, detect_nms_mutex, nms_send_mutex, main_scan_mutex;
condition_variable send_cvt_cv, cvt_detect_cv, detect_nms_cv, nms_send_cv, main_scan_cv;bool is_send_done = false;
bool is_cvt_done = false;
bool is_detect_done = false;
bool is_nms_done = false;
int total_scan_time = 0;void threadSendCom()
{cout << "1. Send Com Thread!" << endl;while (total_scan_time < 5){this_thread::sleep_for(chrono::microseconds(2));unique_lock<mutex> send_cvt_lck(send_cvt_mutex);unique_lock<mutex> nms_send_lck(nms_send_mutex);nms_send_cv.wait(nms_send_lck, [] {return is_nms_done; });cout << " >>>> Is send com: " << total_scan_time << endl;this_thread::sleep_for(chrono::milliseconds(2));is_send_done = true;send_cvt_cv.notify_one();is_nms_done = false;}cout << " Thread 1 end!" << endl;
}void threadImageConvert()
{cout << "2. Img convert Thread!" << endl;while (total_scan_time < 5){this_thread::sleep_for(chrono::microseconds(2));unique_lock<mutex> cvt_detect_lck(cvt_detect_mutex);unique_lock<mutex> send_cvt_lck(send_cvt_mutex);send_cvt_cv.wait(send_cvt_lck, [] {return is_send_done; });cout << " >>>> Is convert image: " << total_scan_time << endl;this_thread::sleep_for(chrono::milliseconds(2));is_cvt_done = true;cvt_detect_cv.notify_one();send_cvt_lck.unlock();is_send_done = false;}cout << "Thread 2 end!" << endl;
}void threadObjectDetection()
{cout << "3. Object detect Thread!" << endl;while (total_scan_time < 5){this_thread::sleep_for(chrono::microseconds(2));unique_lock<mutex> detect_nms_lck(detect_nms_mutex);unique_lock<mutex> cvt_detect_lck(cvt_detect_mutex);cvt_detect_cv.wait(cvt_detect_lck, [] {return is_cvt_done; });cout << " >>>>Is object detect: " << total_scan_time << endl;this_thread::sleep_for(chrono::milliseconds(2));is_detect_done = true;detect_nms_cv.notify_one();cvt_detect_lck.unlock();is_cvt_done = false;}cout << "Thread 3 end!" << endl;
}void threadNMSResample()
{cout << "4. Nms and resample Thread!" << endl;while (total_scan_time < 5){this_thread::sleep_for(chrono::microseconds(2));unique_lock<mutex> nms_send_lck(nms_send_mutex);if (total_scan_time == 0) //第一次,等待主线程唤醒。从而开启循环。{unique_lock<mutex> main_scan_lck(main_scan_mutex);cout << "!!! Waiting here for main thread unlock mutex" << endl;main_scan_cv.wait(main_scan_lck, [] {return is_detect_done; });}else{unique_lock<mutex> detect_nms_lck(detect_nms_mutex);detect_nms_cv.wait(detect_nms_lck, [] {return is_detect_done; });}cout << " >>>> Is NMS resample:" << total_scan_time +1 << endl;this_thread::sleep_for(chrono::milliseconds(2));is_nms_done = true;nms_send_cv.notify_one();is_detect_done = false;total_scan_time += 1;}cout << "Thread 4 end!" << endl;
}int main()
{// Resample --> SendCom --> ImgConvert --> ObjectDetection.// 建立线程函数thread nms_resample_thread(threadNMSResample);thread send_com_thread(threadSendCom);thread img_cvt_thread(threadImageConvert);thread object_detect_thread(threadObjectDetection);// 主线程 解锁并 唤醒通知 threadNMSResample 线程,开启循环。this_thread::sleep_for(chrono::milliseconds(100));{cout << ">>>> Main thread begin!!!!!!" << endl;unique_lock<mutex> main_scan_lck(main_scan_mutex);is_detect_done = true;}main_scan_cv.notify_one();nms_resample_thread.join();object_detect_thread.join();img_cvt_thread.join();send_com_thread.join();cout << " End all" << endl;}
2.2 多线程模式讲解
(1) 多线程开启与主线程唤醒
下面就描述了,多线程间的依赖关系。他们之间形成了闭环。必须要主线程去主动开启通知。 蓝色的箭头表示。
对于主线程去唤醒,我们用条件变量来通知。用的main_scan_cv来进行通知。
(2)单线程需要2个锁,一个主动加锁,一个等待互斥锁释放。
对单个线程,就需要2个锁。比如,图像转换线程。他的数据,来自于发送的信号,SendCom线程处理的结果,才是需要转换的图像。只有图像格式转换完毕之后,目标检测线程,ObjectDetection才能工作。那么,我们就需要两个锁定。
1:主动拥有 cvt_detect_lck。获得cvt_detect_mutex的所有权。把下一个模块,目标检测目标给阻塞住。 对于当前的图像格式转换业务,我们一直等待 上一个模块通知,我们就用条件变量,send_cvt_cv 来wait。直到上一个模块,发起通知,告诉我,发送已经完成,is_send_done。
2:当is_send_done变为true。我们就不用wait,继续执行下面的业务。所以需要send_cvt_lck。 被动拥有和轮询send_cvt_lck的状态解锁。
(3) 运行结果展示
所以,我们最后的结果就是,每个模块,都运行起来。由主函数唤醒一次。剩下就是多线程之间,互相启动的运行过程。我们运行这个目标检测流程5遍,然后退出。下面就是展示运行结果。
如果有用,记得点赞
Qt之主线程与子线程通信(linux下) 转载请注明出处:http://blog.csdn.net/feng1790291543 主线程与子线程通信主要是通过Qt上的Gui按钮,触发使得主线程上的信息 ... Thread类与线程函数 可以使用Thread对象的join方法等待线程执行完毕:主线程(main()函数)中调用Thread对象的join方法,并且Thread对象的线程函数没有执行完毕,主线程会处 ... 多线程(C++/Python) 本文包括一下内容: 通过C++11的标准库进行多线程编程,包括线程的创建/退出,线程管理,线程之间的通信和资源管理,以及最常见的互斥锁,另外对python下多线程的实现 ... 一.为什么会有线程安全问题? 线程安全问题一般是发生再多线程环境,当多个线程同时共享一个全局变量或静态变量做写的操作时候,可能会发生数据冲突问题,也就是线程安全问题,在读的操作不会发生数据冲突问题 下 ... 多线程之间通讯 多线程之间如何实现通讯? wait().notify.notifyAll()方法 wait与sleep区别? JDK1.5-Lock Lock 接口与 synchronized 关键字 ... 目录 知识点1:多线程之间如何实现通讯 1.什么是多线程之间通讯? 2.多线程之间通讯需求 3.代码实现基本实现 (1)共享资源源实体类 (2)输入线程资源 (3)输出线程 (4)运行代码 (5)解决 ... 实验 4 代码注入技术 引言 1.实验说明 代码注入是将用户代码注入到其他进程或者可执行文件中,实现拦截目标进程运行过程的关键信息.改变目标进程或可执行文件原本执行流程等目的 2.实验目的 本实验通过 ... 使用多线程技术可以显著地提高程序性能,本文就讲讲在程序中如何使用工作线程,以及工作线程与主线程通讯的问题. 一 创建线程 使用MFC提供的全局函数AfxBeginThread()即可创建一个工作线程. ... CreateThread CreateThread函数创建一个要在调用进程的地址空间中执行的线程.(MSDN讲解如下) 处理CreateThread ( LPSECURITY_ATTRIBUTES l ... linux下和windows下的 创建线程函数 #ifdef __GNUC__ //Linux #include #define CreateThreadEx(tid,threadFun,args) ...C++多线程之间,线程函数启动之后,多线程依赖的启动和线程唤醒操作。相关推荐
最新文章
热门文章