C++中的类加多线程代码修炼
背景:現(xiàn)在在做一個(gè)目標(biāo)跟蹤的項(xiàng)目,需要實(shí)時(shí)的從工業(yè)相機(jī)中獲取圖像,然后再跟蹤圖像上的目標(biāo)物,由于起初為了測(cè)試跟蹤算法,就把“從相機(jī)獲取圖像”和“跟蹤處理”都放在了主線程中,在實(shí)際測(cè)試時(shí),直接從相機(jī)獲取圖像時(shí),跟蹤處理部分幀率出現(xiàn)周期性卡頓的問題,而直接讀取本地的視頻數(shù)據(jù)時(shí)跟蹤部分幀率很穩(wěn)。因?yàn)椤矮@取圖像”和“跟蹤處理”在一個(gè)線程中,所以兩者是一條線上的螞蚱,要快都快,要慢都滿,所以我沒必要在幀率測(cè)試上花時(shí)間了,另外考慮到,相機(jī)應(yīng)該單獨(dú)出來,一個(gè)是將一些相機(jī)的操作封裝到一個(gè)類里面,另外需要將他放在一個(gè)線程中去,這樣這個(gè)線程只顧獲取圖像就可以不受其他操作的影響。又考慮到以后還會(huì)有數(shù)據(jù)處理這一塊,所以把跟蹤這塊也封裝到一個(gè)類中,也放在一個(gè)單獨(dú)的線程中去。
說自己是C++程序猿真是慚愧,使用C++也快5年了,期間也專門拿兩個(gè)月專門來學(xué)習(xí)C++語(yǔ)法,但是一直以來練習(xí)的太少,導(dǎo)致現(xiàn)在的水平依然很低,今天問我老同事相關(guān)問題,他直接給我發(fā)了一個(gè)“頭上頂著菜葉子的狗”,名副其實(shí)呀,我感覺我就是個(gè)菜狗,哈哈,我要盡早擺脫這個(gè)稱號(hào)。
雖然我的C++功底不深厚,但是還是有一些基礎(chǔ)和經(jīng)驗(yàn)的,我知道第一步需要做的就是把架子搭建起來,然后通過了,然后再往里面填東西。
獲取圖像的類 CaptureThread.h
#ifndef CAPTURETHREAD_H #define CAPTURETHREAD_H namespace FDSST { class CaptureThread { public:CaptureThread();~CaptureThread();void Run();void Stream();void Pause();void Stop();bool quit; private:bool pause_status; }; } #endif // CAPTURETHREAD_H獲取圖像類實(shí)現(xiàn):CaptureThread.cpp
#include <iostream> #include "../include/capturethread.h" #include <windows.h>namespace FDSST { CaptureThread::CaptureThread() {pause_status = false;quit = false; } CaptureThread::~CaptureThread() { } void CaptureThread::Run() {std::cout << "capture_thread!!!" << std::endl;return; } void CaptureThread::Stream() {pause_status = false; }void CaptureThread::Pause() {pause_status = true; }void CaptureThread::Stop() {pause_status = true;quit = true; } }跟蹤類:TrackingThread.h
#ifndef TRACKINGTHREAD_H #define TRACKINGTHREAD_Hnamespace FDSST { class Tracking { public:Tracking();~Tracking();void Run(); }; } #endif跟蹤類實(shí)現(xiàn):TrackingThread.cpp
#include <iostream> #include "../include/trackingthread.h" #include <windows.h> namespace FDSST {Tracking::Tracking(){}Tracking::~Tracking(){}void Tracking::Run(){std::cout << "tracking_thread!!!" << std::endl;return;} }我學(xué)著orb-slam代碼結(jié)構(gòu)的樣子,整出來一個(gè)System類:System.h
#ifndef SYSTEM_H #define SYSTEM_H #include <thread> #include "../include/Trackingthread.h" #include "../include/capturethread.h" namespace FDSST { class Tracking; class CaptureThread;class System { public:System();~System(); private:Tracking* mpTracker;CaptureThread* mpCapturer;std::thread* mptTracking;std::thread* mptCapturing; }; } #endifSyetem.cpp
在System類的構(gòu)造函數(shù)中,創(chuàng)建兩個(gè)線程,將CaptureThread類和Tracking類中的成員函數(shù)Run作為線程的入口
#include "../include/System.h" #include <thread>namespace FDSST {System::System(){mpCapturer = new CaptureThread();mptCapturing = new std::thread(&FDSST::CaptureThread::Run, mpCapturer);std::cout << "Capture thread has been created" << std::endl;mpTracker = new Tracking();mptTracking = new std::thread(&FDSST::Tracking::Run, mpTracker);std::cout << "Tracking thread has been created" << std::endl;}System::~System(){} }我們想象的多線程的樣子都是,代碼執(zhí)行起來之后,兩個(gè)線程中代碼段一直在執(zhí)行,直到到達(dá)代碼控制它結(jié)束的時(shí)候。看我在主函數(shù)中是怎么調(diào)用System的構(gòu)造函數(shù),從而創(chuàng)建兩個(gè)線程的。
我最初的寫法是這樣的:
#include <iostream> #include "../include/System.h" #include <windows.h>int main(int argc, char** argv) {FDSST::System TRACK();return 0; }此時(shí)代碼可以編譯通過,但是我發(fā)現(xiàn)程序并沒有進(jìn)入到System類中的構(gòu)造函數(shù)中去,所以線程被創(chuàng)建的打印未輸出。我很納悶,為啥那塊代碼沒有被執(zhí)行呢?
我就去請(qǐng)教我的老同事,一個(gè)很低調(diào)很牛的boy,我把主函數(shù)和System.cpp的內(nèi)容截圖發(fā)給他,他一看就知道了,他讓我把FDSST::System TRACK();中的括號(hào)去掉,原因是,我在System.cpp中的默認(rèn)構(gòu)造函數(shù)中執(zhí)行創(chuàng)建線程的操作,而如果我的TRACK后面帶有括號(hào),就不會(huì)調(diào)用默認(rèn)構(gòu)造函數(shù),我這種寫法在某些編譯器上應(yīng)該會(huì)出錯(cuò)的。
也就是說,
?? ?如果我使用的是默認(rèn)的構(gòu)造函數(shù)那么就得這樣定義 :FDSST::System TRACK;
?? ?如果我定義了帶參數(shù)的構(gòu)造函數(shù),那就可以定義為:FDSST::System TRACK(paras);
上面的問題解決之后,CaptureThread和TrackingThread類中Run函數(shù)中的打操作只被執(zhí)行了一次,我就又納悶了,咋跟我想象的不一樣,應(yīng)該一直執(zhí)行下去,我繼續(xù)問我那個(gè)老同事事,他說需要加上while(1),我知道了是在Run函數(shù)里面加while(1).上面的Run函數(shù)改成下面這種寫法。
void CaptureThread::Run() {while (1){std::cout << "capture_thread!!!" << std::endl;}return; } void Tracking::Run() {while (1){std::cout << "tracking_thread!!!" << std::endl;}return; }然后我發(fā)現(xiàn)Run函數(shù)中的打印操作還是只執(zhí)行了一次,我又納悶了,又問我那老同事,他說,"你的主函數(shù)結(jié)束了吧”,讓我在main函數(shù)中添加Sleep()函數(shù)。我把主函數(shù)改成下面這個(gè)樣子
#include <iostream> #include "../include/System.h" #include <windows.h>int main(int argc, char** argv) {FDSST::System TRACK();Sleep(10000);return 0; }修改之后,代碼可以一直執(zhí)行了,但是我發(fā)現(xiàn),兩個(gè)線程的輸出呈現(xiàn)交替執(zhí)行的現(xiàn)象,一個(gè)線程執(zhí)行很多次,然后另外一個(gè)線程再執(zhí)行很多次,交替執(zhí)行,像下面這樣。
?我又問我老同事,他讓我在每一個(gè)Run函數(shù)中也加上Sleep(),我就把Run函數(shù)中加上Sleep()
void CaptureThread::Run() {while (1){std::cout << "capture_thread!!!" << std::endl;Sleep(2);}return; } void Tracking::Run() {while (1){std::cout << "tracking_thread!!!" << std::endl;Sleep(2);}return; }這下再執(zhí)行:就正常了,接下來就可以往里面實(shí)現(xiàn)功能了。雖然這個(gè)框架很簡(jiǎn)單,但是在搭建出來的過程中讓我學(xué)到很多東西,所以將難得問題拆分成簡(jiǎn)單的問題,一步一步的來,就可以解決。
總結(jié)
以上是生活随笔為你收集整理的C++中的类加多线程代码修炼的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jQuery笔记——选择器
- 下一篇: C++中public protected