花了三天實現了一個子功能設計,描述如下:從硬碟中搜尋一個時間段抓拍的圖片(jpeg格式),並在GUI上列一個表格顯示所抓拍的圖片的條目,當滑鼠置於form表格上某個條目的上方,該抓拍圖片要在GUI視窗中顯示出來。
本來流程很簡單,但我用單執行緒模式實現後,發現滑鼠在移動的過程中特別卡,後來測試了下jpeg圖片解碼的時間,居然有100ms左右,所以滑鼠卡也就正常了。
我的解決方案是,啟一個解ma線程,與GUI線程獨立開來。:GUI線程通過響應滑鼠事件,將form條目中的jpeg圖片路徑傳遞給解碼線程,解碼線程讀取路徑並解碼該檔案,將解碼後的資料存放區到一塊buffer上,再由GUI去讀資料,並顯示該圖片。
當然,jpeg圖片路徑和解碼資料都加了鎖的。
但是,測試後發現顯示的圖片順序是亂的,後來分析了一下,解碼寫buffer 和GUI 讀buffer是兩個獨立的流程,當GUI讀buffer時,很可能該條目正在解ma,所讀的buffer只不過是上一次解ma後的資料。
有沒有很好的方法可以讓GUI正確顯示該條目的解碼資料呢,這看起來是一個同步問題,實則不是。因為我不能讓GUI線程去等待解碼線程解出資料並顯示,因為這樣做,開解碼線程就是多此一舉。我要求GUI線程是非阻塞的。
最後的解決方案是,在解碼線程裡面加了一個解碼狀態(解碼中、解碼完成),由GUI線程開一個定時器每隔1s判斷這個狀態一次,如果解碼完,則在定時器處理函數內讀取buffer資料並重新整理控制項,否則顯示Loading Picture...
之於GUI的定時器,外行人可能不太理解。因為GUI一般都是事件驅動的,比如滑鼠觸發、網路資訊到達、定時器等。如果同時有幾種事件到達,那麼該響應哪個呢?很顯然對事件來源的並發處理是GUI的核心功能之一。既然是並發,就不難理解定時器響應處理函數時,滑鼠事件依然可以進行。
延伸:
不知道大家是怎麼設計多線程的程式,在此之前我沒有多線程的經驗。但經過這兩天的摸索,有一個非常好的多線程思路和大家分享。
作為C++的迷戀者,我很樂意把線程設計成為一個類,網上有很多有關線程基類的源碼,大致是這樣:
#ifndef THREAD_H_#define THREAD_H_namespace Common{typedef enum{THREAD_STATUS_START = 0,THREAD_STATUS_RUNNING = 1,THREAD_STATUS_STOPPING = 2,THREAD_STATUS_STOPPED = 3,} EnumThreadStatus;class CThread{public:CThread();virtual ~CThread();private:virtual void *ThreadFuncImpl(void) = 0;virtual void PreBeginThread(void);virtual void PostExitThread(void);static void *ThreadRoutine(void *param);public:void Start(int stacksize = 0);void Stop();void InternalStop();private:volatile EnumThreadStatus m_RunningStatus;bool m_InternalStop;};}#endif /* THREAD_H_ */
我們只需繼承這個線程基類,並實現線程處理函數ThreadRoutine(void *param)即可。當然,既然是線程,構造器不能夠公開,只需提供一個單例模式的介面就可以了。
比如下面這個:
class MyThread::Public CThread{protected:MyThread();virtual ~MyThread();static MyThread *m_pThis;private: virtual void *ThreadFuncImpl();public:static MyThread * GetInstance(){if(!m_pThis){m_pThis = new MyThread();}return m_pThis;}static void DelInstance(){if(m_pThis){delete m_pThis;m_pThis = NULL;}}};
因為僅僅是舉例,所以這裡面並沒有涉及業務資料及處理。但對單例模式的理解真的很重要。
最後,你只需在主線程裡面這樣啟動子線程:MyThread::GetInstance();
簡單吧?
另外,處理多線程難免遇到加鎖的情況,如果鎖太多,很容易被隱藏的複雜流程(特別是N多線程)造成死結,這裡我們可以採用一個鎖類簡化加鎖的處理:
#ifndef __AUTOCRI_H__#define __AUTOCRI_H__#include <pthread.h>class CAutoCri{public:CAutoCri( pthread_mutex_t& cs ){m_pCs = &cs;pthread_mutex_lock(m_pCs);}~CAutoCri(){Release();}/*protected:CAutoCri();CAutoCri(const CAutoCri& cri);CAutoCri& operator= (const CAutoCri& cri);*/public:bool Release(){if( m_pCs ){pthread_mutex_unlock(m_pCs);m_pCs = NULL;return true;}return false;}private:pthread_mutex_t* m_pCs;};#endif
尼瑪,CSDN的編輯器有木有這麼2 啊,排版比遊戲論壇都差~~~
下班,回去咯~~