多線程程序操作共享區域(文件)的一點體會

     最近比較忙,很久沒有寫博客了,持續長時間的編程,使得我完全淪爲程序匠人。但是感覺卻不是想別人那麼糟糕,畢業已經快兩年了,我爲我的編程興趣仍然如此強烈而感到欣慰,也對一直以來比較關心的“行業應用軟件架構設計”有了更深的瞭解,這堅定了我的信念!

     今天晚上,終於有了一點點閒暇的時間,就想大家分享下“多線程程序操作共享區域(文件)”的一些體會吧!

 

     多線程相信大家都陌生吧,多線程程序操作共享區域應該也不陌生吧,但是大家是否經歷過多CPU的服務器下同時100個線程,操作離散的文件呢?如果每個線程只負責一個固定的文件,那麼問題也就不是問題了,但是如果離散的文件,有可能同時被多線程都讀寫的,那麼是否能保證文件讀寫的數據一致性、是否能保證數據在存儲的時候由於非次序存儲而導致數據丟失呢?另外,又怎麼解決同一段時間同一個線程操作同一個文件的效率問題呢,如果有方法解決,有怎麼保證不出現上述第一個問題呢?

    

     擺在面前的二個問題,其實都是編寫程序時候,尤其是性能要求比較高的時候,特別需要注意的問題。如下將一一介紹我的一些體會;

 

如何解決多線程多文件操作的數據一致和丟失問題

   解決這個問題,我們要先思考一下,究竟是什麼原因導致這個問題呢?答案很明顯,主要因爲多線程多文件存儲時候的時候頻繁打開和頻繁關閉無次序性導致的,這有點想數據庫一樣,DBMS是怎麼來解決這個問題呢?DBMS有兩個方法,一是事務、二是雙端鎖,其實這兩個方法是一個樣的道理,在這裏我們就不做介紹,有興趣大家可以查尋些其他的資料。這裏我介紹實際應用中我的方法。

   

    我的方法是,保證一個文件在操作的時候,只打開一個實例,打開之後只有一次關閉。

 

    首先來看看,我是如何來設計這樣的文件處理單元,我們起名爲CDataHandlerUint,大家當作其爲結構體就可以了,如下代碼;

   

    由於我們操作XML文件,因此在這個結構體中,我們保存了一個打開的XML文件實例——m_doc。另外一個重要的成員是m_OpenStatusQ這個暫時命名爲XML文件打開請求隊列,用於記錄文件讀寫次數。其他成員隨後會逐一介紹。

 

    如下來看看,這個結構體在線程內部有是怎麼用的,我們還需要一個關鍵的管理這個結構體的成員,CMap<CString,LPCSTR,PCDataHandlerUint,PCDataHandlerUint> m_mapHandlerUint,m_mapHandlerUint就用來管理這個結構體的。其中m_strXmlPath就是這個MAP的KEY,用來直接搜索出CDataHandlerUint的數據處理單元的pointer。

 

    那麼在線程中又怎麼來應用這樣的一個成員呢?看下如下這個線程的處理過程就明白了;

 

    UINT32 DataHandlerThread(LPVOID pThis){

          (1) 獲取要操作的文件路徑

          (2) 通過文件路徑,獲取保存在m_mapHandlerUint的Pointer.

          (3) 如果這個Pointer爲NULL,重新NEW,調用m_OpenStatusQ.push(true),之後並添加到MAP中。

         (4)如果這個Pointer不爲NULL,調用m_OpenStatusQ.push(true)。

          ............

          (5) 調用m_OpenStatusQ.pop(),之後檢測m_OpenStatusQ的size ,如果size爲0,保存並關閉XML文件,否則,在根據m_dwOldTicks判斷是否超時,如果超時同樣保存並關閉XML文件,否則結束函數

    }

 

     這樣就應用了MAP加上queue順利的解決了這個問題,大家看了之後,仔細想想吧!

 

如果線程操作文件時,如果文件存在一定順序,那麼怎麼提高效率呢?

     如果一個線程序遇到一個這樣的文件系列怎麼辦,如下文件系列;

      A.xml

      A.xml

      B.xml

      B.xml

      C.xml

      ......

     從這裏可以看出,文件是有順序的,那麼如何提高效率呢?

     答案就是,儘量減少文件打開和關閉次數,重複利用已經打開的文件句柄!

 

     這裏程序設計的方法其實很簡單,只需獲取上一次操作文件句柄,並在上次操作的時候不關閉文件,關閉文件的操作放在調用之外,這樣當發現兩個句柄一樣的時候,即調用保存並關閉,當然這裏考慮到第一個問題,因此保存並關閉的條件仍然是調用m_OpenStatusQ.pop(),之後檢測m_OpenStatusQ的size ,如果size爲0,保存並關閉XML文件,否則,在根據m_dwOldTicks判斷是否超時,如果超時同樣保存並關閉XML文件,否則結束函數。

 

    上述的兩個問題,兩個方法,只介於本人的體會,肯定還有更好的方法,如大家有興趣可以聯繫我本人,方便更深一步的探討。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章