1. 程式人生 > >主執行緒,子執行緒資源衝突,解決方案

主執行緒,子執行緒資源衝突,解決方案

問題描述,  我開發的任性動圖軟體,曾經遇到過這樣的問題:

     任性動圖有一個功能是塗鴉功能,就是將你的塗鴉過程生成動圖,怎麼實現的呢?

     有一個主顯示記憶體,用以顯示介面影象

     有一個輔顯示記憶體,用以生成動圖時,繪製動圖

     因為要繪製塗鴉,所以

     開闢了一個塗鴉記憶體,將塗鴉繪製在這個記憶體上,然後再分別拷貝到主次記憶體上。

 因為要生成動圖,而且生成的過程中,要適時塗鴉,所以啟用執行緒的方式。   

     開闢了一個執行緒,這個執行緒負責將塗鴉過程,生成GIF動圖

     主執行緒複雜繪製塗鴉,然後將繪製好的塗鴉記憶體,拷貝到顯示記憶體上。

問題來了:生成的GIF動圖,發現很多時候,某一幀是空白的,也就是說,那一幀 並沒有將塗鴉繪製到動圖上。

原因:

    後來經分析,原因很可能是這兒產生了衝突 。

        主執行緒繪製塗鴉,

        主執行緒將塗鴉記憶體拷貝到主記憶體上

        子執行緒將塗鴉記憶體拷貝到輔記憶體上

        這時就有可能產生衝突了: 主執行緒在繪製塗鴉記憶體的時候,正好遇到子執行緒想將塗鴉記憶體拷貝到輔記憶體上,也就是主執行緒和子執行緒同時操作塗鴉記憶體,這樣就產生矛盾了,由此引發了這個問題。

解決:

1 初始化訊號

HANDLE m_hDrawScrawl ; //自動復原 有訊號  保證生成動圖過程中 繪製的完整性  
m_hDrawScrawl = CreateEvent(NULL, TRUE, TRUE, NULL);  //

主執行緒中,塗鴉記憶體處理過程,設定為無訊號

繪製塗鴉函式中,繪製過程中,設定為無訊號,繪製結束後,再置位有訊號。

DrawScrawl(UINT nFlags, CPoint nPoint){

	//塗鴉
	
	ResetEvent(m_hDrawScrawl);//設定為無訊號
        Draw()//繪製塗鴉過程。。。。。
        //。。。。。
       SetEvent(m_hDrawScrawl);

}


主執行緒塗鴉拷貝過程設定為無訊號

		ResetEvent(m_hDrawScrawl);//設定為無訊號

		dcMem.TransparentBlt(0, 0, m_rcbmMem.Width(), m_rcbmMem.Height(), &dcTuyaMem, 0, 0, m_rcbmMem.Width(), m_rcbmMem.Height(), RGB(255, 255, 255));



		if (m_bTuya&&m_nShapeStyle == 1){
			dcMem.TransparentBlt(0, 0, m_rcbmMem.Width(), m_rcbmMem.Height(), &dcTuyaMem_Sec, 0, 0, m_rcbmMem.Width(), m_rcbmMem.Height(), RGB(255, 255, 255));
		}
		SetEvent(m_hDrawScrawl);//設定為有訊號


3  子執行緒等待主執行緒的塗鴉記憶體操作完畢後,再操作

			WaitForSingleObject(m_hDrawScrawl, 4000);

			dcMem.TransparentBlt(pMiddleChunk->Left, pMiddleChunk->Top, pMiddleChunk->Width, pMiddleChunk->Height, &dcTuyaMem, pMiddleChunk->Left, pMiddleChunk->Top, pMiddleChunk->Width, pMiddleChunk->Height, RGB(255, 255, 255));
			



當然,這隻考慮了一層,只考慮了子執行緒處理時,一定要等主執行緒完畢後才可,沒有考慮子執行緒處理塗鴉記憶體時,防止主執行緒也在處理。因為我的子執行緒只是個拷貝,所以沒有雙向考慮。

要想主執行緒、輔執行緒都不打擾。

可能要試試下面的策略

設定同一個訊號量,用這個訊號量進行控制,主執行緒等待子執行緒完畢後,再進行,子執行緒等待主執行緒完畢後,再進行。

hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 

主執行緒:

   WaitForSingleObject(hEvent,INFINITE)

   ResetEvent(hEvent)

   .....

   SetEvent(hEvent)

輔執行緒:

   WaitForSingleObject(hEvent,INFINITE)
   ResetEvent(hEvent)
   .....
   SetEvent(hEvent)

比如:

子執行緒繪圖函式  DrawGifOnDC(memDC, i);  

主執行緒繪圖函式 DrawXml();

兩者有衝突,可以這麼解決

子執行緒:

				  WaitForSingleObject(m_hDrawxml, INFINITE);
				 
				  ResetEvent(m_hDrawxml);
				  DrawGifOnDC(memDC, i);
				  SetEvent(m_hDrawxml);

主執行緒
			WaitForSingleObject(m_hDrawxml, INFINITE);
			ResetEvent(m_hDrawxml);
			
			DrawXml();

			SetEvent(m_hDrawxml);