<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)  編輯  收藏 所屬分類: 網絡游戲
     
    主站蜘蛛池模板: 一个人看的免费视频www在线高清动漫| 丁香六月婷婷精品免费观看| 免费爱爱的视频太爽了| 免费看黄网站在线看 | 国产在线观看xxxx免费| 亚洲人成网站日本片| 亚洲Av无码国产情品久久| 99在线观看免费视频| 亚洲成a人无码亚洲成www牛牛| 国产成人亚洲影院在线观看| 在线观看永久免费| 免费人成视频在线播放| 久久精品国产亚洲AV电影| 国产美女无遮挡免费视频| 日韩电影免费观看| 国产精品亚洲精品日韩动图| 亚洲人成亚洲精品| 午夜亚洲福利在线老司机| 最近中文字幕大全免费视频| 一区二区三区精品高清视频免费在线播放 | 亚洲国产精品久久久久网站| 国产一区二区三区免费视频| 最近免费mv在线电影| 亚洲免费一区二区| 亚洲精品第一国产综合亚AV| 亚洲日本va午夜中文字幕一区| 亚洲AV无码一区二区三区在线观看| 18未年禁止免费观看| 中文字幕乱理片免费完整的| 鲁死你资源站亚洲av| 亚洲一区二区三区免费| 中文字幕 亚洲 有码 在线| 亚洲av丰满熟妇在线播放| 亚洲国产激情一区二区三区| 在线观看日本免费a∨视频| 久久久久久久99精品免费 | a级毛片高清免费视频就| 久久久久无码精品亚洲日韩| 日韩亚洲国产二区| 日韩一级视频免费观看| 色影音免费色资源|