<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    游戲策劃咨訊
    做一個游戲并不難,難的是做一個好游戲;完美在于積累!
     

    線程同步和服務器數據保護

    最近因為自己主持的項目出現些問題,太忙了,所以好久都沒有繼續寫東西和大家進行探討制作開發部分了。在這一節中就要向大家介紹另外一個重要的部分,并且也是最頭疼的部分:線程同步和數據保護。

    關于線程的概念我在前面的章節中已經介紹過了,也就在這里不累贅—“重復再重復”了。有一定線程基礎的人都知道,線程只要創建后就如同脫韁的野馬,對于這樣的一匹野馬我們怎么來進行控制和處理呢?簡單的說,我們沒有辦法進行控制。因為我們更本就沒有辦法知道CPU什么時候來執行他們,執行他們的次序又是什么?

    有人要問沒有辦法控制那我們如何是好呢?這個問題也正是我這里要向大家進行解釋和說明的,雖然我們不能夠控制他們的運行,但我們可以做一些手腳來達到我們自己的意志。

    這里我們的做手腳也就是對線程進行同步,關于同步的概念大家在《操作系統》中應該都看過吧!不了解的話,我簡單說說:讀和寫的關系(我讀書的時候,請你不要在書上亂寫,否則我就沒有辦法繼續閱讀了。)

    處理有兩種:用戶方式和內核方式。
    用戶方式的線程同步由于有好幾種:原子訪問,關鍵代碼段等。

    在這里主要向大家介紹關鍵代碼段的處理(我個人用的比較多,簡單實用)。先介紹一下它的一些函數,隨后提供關鍵代碼段的處理類供大家參考(比較小,我就直接貼上來了)

    VOID InitializeCriticalSection(    //初始化互斥體
      LPCRITICAL_SECTION lpCriticalSection  // critical section
    );

    VOID DeleteCriticalSection(        //清除互斥體
      LPCRITICAL_SECTION lpCriticalSection   // critical section
    );

    VOID EnterCriticalSection(         //進入等待
      LPCRITICAL_SECTION lpCriticalSection  // critical section
    );

    VOID LeaveCriticalSection(         //釋放離開
      LPCRITICAL_SECTION lpCriticalSection   // critical section
    );

    以上就是關于關鍵代碼段的基本API了。介紹就不必了(MSDN)。而我的處理類只是將這幾個函數進行了組織,也就是讓大家能夠更加理解關鍵代碼端
    .h
    class   CCriticalSection                //共享變量區類
    {
    public:
    CCriticalSection();
    virtual ~CCriticalSection();
    void   Enter();                   //進入互斥體
    void   Leave();                  //離開互斥體釋放資源
    private:
       CRITICAL_SECTION  g_CritSect;
    };
    .cpp
    CCriticalSection::CCriticalSection()
    {
    InitializeCriticalSection(&g_CritSect);
    }

    CCriticalSection::~CCriticalSection()
    {
    DeleteCriticalSection(&g_CritSect);
    }

    void  CCriticalSection::Enter()
    {
    EnterCriticalSection(&g_CritSect);
    }

    void  CCriticalSection::Leave()
    {
        LeaveCriticalSection(&g_CritSect);
    }
    由于篇幅有限關鍵代碼段就說到這里,接下來向大家簡單介紹一下內核方式下的同步處理。
    哎呀!這下可就慘了,這可是要說好多的哦!書上的羅羅嗦嗦我就不說了,我就說一些我平時的運用吧。首先內核對象和一般的我們使用的對象是不一樣的,這樣的一些對象我們可以簡單理解為特殊對象。而我們內核方式的同步就是利用這樣的一些特殊對象進行處理我們的同步,其中包括:事件對象,互斥對象,信號量等。對于這些內核對象我只向大家說明兩點:
    1.內核對象的創建和銷毀
    2.內核對象的等待處理和等待副作用

    第一:內核對象的創建方式基本上而言都沒有什么太大的差別,例如:創建事件就用HANDLE CreateEvent(…..),創建互斥對象 HANDLE CreateMutex(…….)。而大家注意的也是這三個內核對象在創建的過程中是有一定的差異的。對于事件對象我們必須明確指明對象是人工對象還是自動對象,而這種對象的等待處理方式是完全不同的。什么不同下面說(呵呵)。互斥對象比較簡單沒什么說的,信號量我們創建必須注意我們要定義的最大使用數量和初始化量。最大數量>初始化量。再有如果我們為我們的內核對象起名字,我們就可以在整個進程中共用,也可以被其他進程使用,只需要OPEN就可以了。也就不多說了。

    第二:內核對象的等待一般情況下我們使用兩個API:
    DWORD WaitForSingleObject(        //單個內核對象的等待
          HANDLE hHandle,        // handle to object
          DWORD dwMilliseconds   // time-out interval
    );

    DWORD WaitForMultipleObjects(     //多個內核對象的等待
          DWORD nCount,             // number of handles in array
          CONST HANDLE *lpHandles,  // object-handle array
          BOOL fWaitAll,            // wait option
          DWORD dwMilliseconds      // time-out interval
    );
    具體怎么用查MSDN了。
    具體我們來說等待副作用,主要說事件對象。首先事件對象是分兩種的:人工的,自動的。人工的等待是沒有什么副作用的(也就是說等待成功后,要和其他的對象一樣要進行手動釋放)。而自動的就不一樣,但激發事件后,返回后自動設置為未激發狀態。這樣造成的等待結果也不一樣,如果有多個線程在進行等待事件的話,如果是人工事件,被激活后所有等待線程成執行狀態,而自動事件只能有其中一個線程可以返回繼續執行。所以說在使用這些內核對象的時候,要充分分析我們的使用目的,再來設定我們創建時候的初始化。簡單的同步我就說到這里了。下面我就將將我們一般情況下處理游戲服務器處理過程中的數據保護問題分析:

    首先向大家說說服務器方面的數據保護的重要性,圖例如下:

    用戶列表

                                      用戶刪除

                                      用戶數據修改
                                      
                                      使用數據


    加入隊列

    對于上面的圖例大家應該也能夠看出在我們的游戲服務器之中,我們要對于我們用戶的操作是多么的頻繁。如此頻繁的操作我們如果不進行處理的話,后果將是悲慘和可怕的,舉例:如果我們在一個線程刪除用戶的一瞬間,有線程在使用,那么我們的錯誤將是不可難以預料的。我們將用到了錯誤的數據,可能會導致服務器崩潰。再者我們多個線程在修改用戶數據我們用戶數據將是沒有辦法保持正確性的。等等情況都可能發生。怎么樣杜絕這樣的一些情況的發生呢?我們就必須要進行服務器數據的保護。而我們如何正確的保護好數據,才能夠保持服務器的穩定運行呢?下面說一下一些實際處理中的一些經驗之談。

    1.我們必須充分的判斷和估計我們服務器中有那些數據要進行數據保護,這些就需要設計者和規劃者要根據自己的經驗進行合理的分析。例如:在線用戶信息列表,在線用戶數據信息,消息列表等。。。。。

    2.正確和十分小心的保護數據和正確的分析要保護的數據。大家知道我們要在很多地方實現我們的保護措施,也就是說我們必須非常小心謹慎的來書寫我們的保護,不正確的保護會造成系統死鎖,服務器將無法進行下去(我在處理的過程中就曾經遇到過,頭都大了)。正確的分析要保護的數據,也就是說,我們必須要估計到我們要保護的部分的處理能夠比較快的結束。否則我們必須要想辦法解決這個問題:例如:
             
             DATA_STRUCT  g_data;
             CRITICAL_SECTION  g_cs;

             EnterCriticalSection(&g_cs);
             SendMessage(hWnd,WM_ONEMSG,&g_data,0);
             LeaveCriticalSection(&g_cs);
    以上處理就有問題了,因為我們不知道SendMessage()什么時候完成,可能是1/1000豪秒,也可能是1000年,那我們其他的線程也就不用活了。所以我們必須改正這種情況。

             DATA_STRUCT  g_data;
             CRITICAL_SECTION  g_cs;

             EnterCriticalSection(&g_cs);
             PostMessage(hWnd,WM_ONEMSG,&g_data,0);
        LeaveCriticalSection(&g_cs);

    或者        DATA_STRUCT  temp_data;

             EnterCriticalSection(&g_cs);
             temp_data = g_cs;
             LeaveCriticalSection(&g_cs);
             SendMessage(hWnd,WM_ONEMSG,& temp_data,0);

       3.最好不要復合保護用戶數據,這樣可能會出現一些潛在的死鎖。


    簡而言之,服務器的用戶數據是一定需要進行保護,但我們在保護的過程中就一定需要萬分的小心和謹慎。這篇我就說到這里了,具體的還是需要從實踐中來進行學習,下節想和大家講講服務器的場景處理部分。先做事去了。呵呵!!有好的想法和建議的和我交流探討,先謝謝了。

    posted on 2005-02-13 11:54 藍色雪焰 閱讀(319) 評論(0)  編輯  收藏 所屬分類: 網絡游戲
     
    主站蜘蛛池模板: 精品成人一区二区三区免费视频| 亚洲日本VA午夜在线影院| h视频在线免费观看| 国产又大又黑又粗免费视频| 亚洲AV无码无限在线观看不卡| 精品福利一区二区三区免费视频 | 二级毛片免费观看全程| 午夜亚洲av永久无码精品| 美女视频黄.免费网址| 亚洲日本中文字幕天堂网| h在线看免费视频网站男男| 久久亚洲2019中文字幕| 一边摸一边爽一边叫床免费视频| 亚洲日韩在线观看| GOGOGO高清免费看韩国| 亚洲AV永久青草无码精品| 99国产精品免费观看视频| 亚洲人成网站在线观看播放青青| 中国在线观看免费高清完整版| 亚洲色一区二区三区四区| 四虎影视永久免费视频观看| 一个人看的www视频免费在线观看| 77777亚洲午夜久久多人| 999久久久免费精品播放| 激情综合亚洲色婷婷五月| 国产美女无遮挡免费视频 | a级毛片毛片免费观看久潮 | 久久精品国产亚洲夜色AV网站| 久久精品视频免费看| 亚洲精品免费网站| 亚洲精品无码99在线观看 | 亚洲AV无码一区二区三区鸳鸯影院| 免费欧洲毛片A级视频无风险| 国产精品高清免费网站| 亚洲天堂中文字幕| 特级淫片国产免费高清视频| 国产裸体美女永久免费无遮挡| 精品亚洲成a人片在线观看少妇| 日韩免费福利视频| 伊人久久免费视频| 青青青亚洲精品国产|