• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            ACG狂人

            其實我更愛姐汁...

            #

            封裝MySQL時解決的兩個字符集問題

            在我開始封裝MySQL C API時,真的沒有想過居然會在字符集問題上連續(xù)卡殼,折騰了一下午+一晚上,終于搞定這些問題。下面記錄一下我遇見的問題以及解決辦法,以作備忘。
            首先遇見的當(dāng)然是中文亂碼問題。這個問題相對來說資料比較多,文檔寫得應(yīng)該也是很清楚的,但是我沒心思看,靠猜搞定。我首先設(shè)置MySQL服務(wù)器的默認字符集為UTF8,并保證我操作的表中的列字符集也是UTF8,然后重啟MySQL服務(wù),并嘗試用mysql_query("INSERT INTO TestTable VALUES('你好')")來寫入,結(jié)果失敗在預(yù)料之中。我猜可能可以使用類似"INSERT INTO TestTable VALUES('\0x2734\0x3432')"這樣的方式寫入中文,但這樣太丑了,也沒有實用價值,我堅決不會去用。我又嘗試使用MultiByteToWideChar去做,甚至使用了Qt的QTextCodec去轉(zhuǎn)換“你好”這兩個字,結(jié)果依然失敗。這就有些蹊蹺了,我決定調(diào)用mysql_character_set_name()看看到底有沒有正確的設(shè)置成UTF8格式,讓我意料之外的是:結(jié)果是latin1,這難道是拉丁字符集??我查看了一下API函數(shù)的相關(guān)說明,發(fā)現(xiàn)這里獲取到的是客戶端鏈接的字符集,我突然覺得,也許MySQL可以自動的在客戶端與服務(wù)器之間的字符集進行轉(zhuǎn)化!說做就做,我查到了可以用mysql_options()或者mysql_set_character_name()函數(shù)來設(shè)置客戶端鏈接字符集,但這兩個函數(shù)用的時機分別在調(diào)用mysql_real_connect()之前或之后。我將客戶端鏈接設(shè)置成gb2312字符集,這是VC中支持中文的標(biāo)準(zhǔn)字符集之一(另一個標(biāo)準(zhǔn)是UTF16,需要用wchar_t  wstring和常量字符串前的L),結(jié)果,當(dāng)然是非常正確的插入中文啦,呵呵!
            正當(dāng)我覺得下面的封裝肯定會順湯順?biāo)畷r,在封裝基本完成的時候,我發(fā)現(xiàn)控制臺不能輸出我從MySQL取出的中文了!這太奇怪了,輸出英文就沒有問題,而中文雖然的確被準(zhǔn)確無誤的讀入了std::string中(通過單步調(diào)試和ofstream得到確認),然而輸出到cout中卻會出錯。為什么文件流沒問題,控制臺流會出問題呢?我跟蹤了代碼,發(fā)現(xiàn)在fputc()函數(shù)中出現(xiàn)了問題。另一個奇特的地方,就是在mysql_init()函數(shù)被調(diào)用之前,cout可以正確輸出中文,但調(diào)用之后就不能輸出,iostate被賦予4值,即badbit。我求了一下google,發(fā)現(xiàn)sputc()中的一個_nolock_write()函數(shù)是msvcrtd.lib中的函數(shù),暈了,我在單步調(diào)試中也發(fā)現(xiàn)就是這里有問題,確切的說,mysql_init()函數(shù)被調(diào)用后,_nolock_write()函數(shù)就會出錯。哈哈,總結(jié)出了這些特點之后,我已經(jīng)隱約猜到了是哪里的問題了,還記得前幾日才寫的blog里的東西,我由于想要將libmysql.lib換成mysqlclient.lib靜態(tài)庫,所以便禁掉了msvcrtd.lib庫,我肯定這里面有關(guān)聯(lián)。
            到底是什么原因呢?我覺得,由于這個MySQL的SDK不是我自己編譯的,mysqlclient.lib里面調(diào)用crt函數(shù)時,對字符集的本地化做了設(shè)置,由于是歐美的字符集設(shè)置,所以一旦我調(diào)用了mysqlclient.lib里的函數(shù),就無法再顯示中文了。
            猜出了問題的根源,那么如何解決這個問題呢?我可以肯定的是,使用std::cout.imbue(std::locale())是行不通的,那么下面就是列出的幾個辦法:
            1、使用人家編譯好的動態(tài)庫,libmysql.lib,并將libmysql.dll拷貝過來,由于動態(tài)庫和你的程序共享crt dll,因此字符集設(shè)置應(yīng)該會是一致的。
            2、如果你還是想用靜態(tài)庫,可以考慮自己下載源碼并編譯一遍,這是根本的解決辦法。
            3、如果你可以自己編譯,且想用mysqlclient.lib,那么就重新編譯mysqlclient吧,動態(tài)靜態(tài)都可以。不過官網(wǎng)上下載的編譯好的mysqlclient.lib是靜態(tài)的,不能使用。

            我最終的解決辦法是第1種,因為比較懶,不想自己再去編譯了,呵呵。

            posted @ 2009-10-09 22:29 釀妹汁 閱讀(1972) | 評論 (3)編輯 收藏

            原來靜態(tài)庫是這樣鏈接的

            最近在win32平臺下封裝MySQL的客戶端C API時,出現(xiàn)的問題著實讓我頭痛了個把小時,不過多虧這一來,我終于明白了靜態(tài)庫是怎樣鏈接的,結(jié)合了以前我對動態(tài)庫與靜態(tài)庫之間進行比較的一些測試結(jié)論,也明白了為什么靜態(tài)庫需要這樣的設(shè)計。不由感嘆一下古人的那句話:“挫折果真是成功的母親。”(好大霧^_^!)
            閑話不多說,記錄一些關(guān)鍵點,首先是靜態(tài)鏈接到底和動態(tài)鏈接有哪些不太容易發(fā)現(xiàn)的區(qū)別呢?我來假設(shè)libA依賴libB,那么我的執(zhí)行文件在使用libA的時候也需要導(dǎo)入libB才能正確鏈接,但若dllA依賴libB的話,則只需導(dǎo)入dllA就可以。我在一開始用MySQL時使用的內(nèi)嵌數(shù)據(jù)庫模式,所以導(dǎo)入的是那個libmysql.dll動態(tài)庫,因此沒出現(xiàn)問題。而換上了mysqlclient.lib后,居然告訴我沒有找到socket相關(guān)的實現(xiàn),即“無法解析的外部符號”這類錯誤,于是乎我只有加上ws2_32.lib庫才能通過。
            為什么這樣設(shè)計?原因其實跟靜態(tài)庫的連接方式有關(guān),由于靜態(tài)庫直接將函數(shù)實現(xiàn)和全局靜態(tài)變量導(dǎo)入到包含它的執(zhí)行體中,所以在多層多重的庫包含中就會有大量重定義的問題存在,想想你在一個靜態(tài)庫中用了單件模式,那么其他庫又包含你這個庫,最后exe又包含所有這些庫,最終形成菱形依賴,如果靜態(tài)庫不這樣設(shè)計的話,問題就會像C++的多重繼承問題一樣。之所以靜態(tài)庫這樣設(shè)計,跟C++的虛擬繼承思想簡直如出一轍。(我知道這段話其實只有已經(jīng)懂了的人才能看得懂,不過沒辦法,我表達能力挺笨的...)

            還有個極度郁悶的地方是:mysqlclient.lib中的libcmtd.lib和msvcrtd.lib這對活寶居然也被鏈接進去了,我這邊首先需要忽略這兩個默認庫,然后再包含msvcrtd.lib才可以。我不知道為啥sdk提供的靜態(tài)庫非得在c runtime link的方式上跟一般人過不去,又懶得去自己編譯,哎!將就一下就這么用吧......

            posted @ 2009-10-06 21:30 釀妹汁 閱讀(1590) | 評論 (0)編輯 收藏

            PhysX動工

            PhysX物理引擎是眾多可選的物理引擎之一,但為什么我要選PhysX而不是其他呢?也許下面的一些論述純粹是自己的意淫,因為并沒有真正的去測試過這些,不對之處請看官們指點一二,免讓我這個糊涂蟲誤入歧途。

            選擇PhysX的原因是這樣的,拿目前與PhysX對立的Havok引擎來做比較,Intel和AMD-ATI支持的Havok引擎主要致力于CPU運算物理效果,而nvidia獨推的cuda架構(gòu)和PhysX引擎則主要致力于GPU或GPU群集運算,且不談在游戲客戶端的物理效果到底是用GPU好還是CPU好(這跟你GPU是否忙得過來有關(guān)),由于目前正在攻關(guān)的游戲開發(fā)項目需求較為特殊,我在這里只關(guān)注服務(wù)器方面的高性能剛體物理運算問題。nvidia近兩年推出的cuda架構(gòu)群集不斷走向成熟,這種群集是用GPU陣列作為運算核心的超級并行計算機,在物理運算方面與CPU所組成的群集不是一個檔次,總體運算性能甚至超過同等價位的CPU群集近百倍!我考慮將物理運算完全交給獨立的GPU群集,讓CPU去做那些它所擅長的工作。也許這正是符合了nvidia推廣cuda的思想吧,因此看著PhysX對我就有格外的吸引力,所以當(dāng)然是奮力研究了。

            于是去了nvidia官網(wǎng)的Download區(qū),先搞下來三個東西:cuda sdk、cuda toolkit、cuda 那個啥??沒啥,只是隨便看看,順帶裝了下cuda顯卡驅(qū)動,呵呵。于是又下了PhysX的SDK,好了,等一切安裝完畢,設(shè)置好包含目錄和庫目錄后就開始了我的HelloWorld歷程!寫一個PhysX的HelloWorld較為麻煩,要有能看得見的效果還得累一陣子,于是直接拿sample里的教程進行修改,第一步當(dāng)然是戳一戳剛體碰撞了,發(fā)現(xiàn)PhysX的抽象建模比我料想的好很多,基本上我所考慮到的它全有了,而且理解起來非常簡單。

            PhysX的建立過程只有很少量的代碼,首先是建立一個SDK對象,然后建立碰撞場景NxScene。
            在PhysX中,一個可以檢測碰撞的對象叫做NxActor,這個NxActor的建立除了需要一個指定的NxScene以外,還需要一些描述信息,這些描述如下:
            碰撞對象的外形描述: 統(tǒng)一用的是NxXXXShapeDesc的命名方式,譬如NxBoxShapeDesc,甚至NxTranglesMeshShapeDesc之類的,你可以將任意的3D形態(tài)做成NxActor的外形,物理引擎會根據(jù)這個外形的面來做碰撞檢測和質(zhì)點的根據(jù)。
            碰撞對象的體型描述: 即NxBodyDesc,用于記錄一個碰撞對象的質(zhì)量、初始速度、初始沖量等信息,感覺似乎是將一個對象作為一個質(zhì)點考慮時的一些數(shù)據(jù),總之,沒有這個描述的話,碰撞對象會被視為一個靜態(tài)對象,即不能主動變動坐標(biāo)的物體,亦不會存在質(zhì)量和速度等信息。
            材質(zhì)ID:材質(zhì)是在物理引擎的NxScene中建立的,每個對象所使用的材質(zhì)ID都是指的是NxScene中的第幾個材質(zhì)。材質(zhì)包括了摩擦力和彈力之類的信息。

            恩,目前還沒看到j(luò)oint的使用,估計就是連接兩個碰撞對象的一種力學(xué)關(guān)系吧,來回擺動的吊籃,上面又要能站人,肯定需要這個。這樣看來,剛體基本上不存在什么問題了,而在我目前攻關(guān)的服務(wù)器部分,只需要剛體部分,因此PhysX的學(xué)習(xí)目前到此為止了,接下來就是對游戲服務(wù)器的框架設(shè)計上多下功夫了。

            posted @ 2009-09-03 01:28 釀妹汁 閱讀(1939) | 評論 (2)編輯 收藏

            異常處理的可惡陷阱

            也許這個錯誤是很幼稚的,但是他著實難住了我好幾個小時,一度我還以為永遠解不開這個謎題了(*o*),情況是這樣的,異常在拋出之后,到達處理異常的catch域,但這時上下文必須依然有效才行,否則catch將接收不到拋出的異常。具體代碼如下:
                try
                
            {
                    moeutil::simple_pool spool(
            32);
                    
            void* p1 = spool.malloc(15);
                    
            void* p2 = spool.malloc(102);
                    
            void* p3 = spool.malloc(154);
                    
            void* p4 = spool.malloc(7);
                    
            void* p5 = spool.malloc(7);
                    
            void* p6 = spool.malloc(70);
                    
            //std::cout<<p1<<'\n'<<p2<<'\n'<<p3<<'\n'<<p4<<'\n'<<p5<<'\n'<<p6<<std::endl;
                    spool.free(p1);
                    spool.free(reinterpret_cast
            <char*>(p2)+2);
                    spool.free(p3);
                    spool.free(p4);
                    spool.free(p5);
                    spool.free(p6);

                }
            catch (moeutil::Exception& e){
                    std::cout
            <<e.what()<<std::endl;
                }
            這是一個簡易的內(nèi)存池類,其中simple_pool的析構(gòu)函數(shù)會拋出異常,然后free函數(shù)也會拋出異常。析構(gòu)函數(shù)可以檢測是否有內(nèi)存泄漏,而free函數(shù)是檢測到無效的傳入指針時會拋出異常。析構(gòu)拋出異常是沒問題的,但是free拋出異常的時候問題就來了,當(dāng)free拋出異常時,由于會脫離try塊,所以spool也會被析構(gòu),這樣就會陷入麻煩,由于沒有全部free,所以析構(gòu)本身也會拋出異常,導(dǎo)致了類似于異常迭代的情況。也就是說,在throw一個異常的過程中又一次觸發(fā)了異常。于是windows系統(tǒng)的debug error對話框出現(xiàn)了,而且是出現(xiàn)在throw那一行。
            此隨筆用于提醒自己勿犯第二次!

            posted @ 2009-08-02 17:12 釀妹汁 閱讀(678) | 評論 (1)編輯 收藏

            使用boost庫需要一定的素質(zhì)

                    可能由于在幾個博客上發(fā)布了一些boost庫使用心得的關(guān)系,最近總是被一些相關(guān)的詢問郵件騷擾,而提問者問的問題卻又讓我不知道如何回答才好,或者說根本沒有辦法回答。一些問題根本就不該問的,所以便發(fā)些感慨,還望看了本人一些心得又不禁想問一些偷懶問題的各位手下留情,不要再問我一些奇怪的問題了(*w*)!
                    我們學(xué)習(xí)并使用boost庫的目的是簡化編程,這并不代表簡化到你根本不需要去理解原理的地步。我想,如果您希望很好的駕馭boost庫的話,那么請對您自己發(fā)發(fā)狠努力編寫代碼積累經(jīng)驗,直到您認為boost庫中30%的功能您都能夠親自動手實現(xiàn)的時候,才嘗試去使用它。類似“怎么讓線程組和asio合作使用”之類的問題,我覺得很囧,而且問的人還非常多,給代碼都還迷糊。我覺得您想用asio,請先嘗試編寫線程類和IOCP框架的應(yīng)用程序,如果您連線程類都寫不好,或者連一個多線程死鎖和共享區(qū)都不能安全排除的話,請先打打基礎(chǔ)吧。
                    boost庫是一個非常有深度的東西,也是智慧的結(jié)晶,有很多東西在一定條件下您可以不用深究,但是起碼的30%則必須刨根問底,這30%實際上都是很基礎(chǔ)的東西,切不可急于一時而至整個工程最終因為boost的一點小問題卡殼,倘若無法駕馭,則不如不用,再急我也沒法幫您了!

            posted @ 2009-07-30 18:19 釀妹汁 閱讀(18993) | 評論 (26)編輯 收藏

            VC編譯器中的一些編譯時命令備忘

             

            // 加載靜態(tài)庫
            #pragma comment(lib, "路徑+LIB庫名")

            // 禁止1221號警告
            #pragma warning(disable: 1221)

            // 導(dǎo)入并加載DLL exe之類的二進制動態(tài)庫
            #import "路徑+二進制庫名"

            // 將ClassName類中的s_Data靜態(tài)成員變量定義在頭文件中時防止重定義
            __declspec(selectany) int ClassName::s_Data = 0;

            // 當(dāng)用戶使用void func()函數(shù)時,編譯器將作出警告,并顯示“不推薦使用該函數(shù)”字樣
            __declspec(deprecated("不推薦使用該函數(shù)")) void func();

            posted @ 2009-07-30 18:00 釀妹汁 閱讀(968) | 評論 (0)編輯 收藏

            記錄一下C++標(biāo)準(zhǔn)流感悟

                    今天終于完成了自己的日志庫核心的幾個類和算法,折騰了許久,感覺安全性很好,一些多線程的死鎖問題已經(jīng)逐個排除了。由于需要跟C++標(biāo)準(zhǔn)庫的輸入輸出流共事,所以么總算自認為理解了C++標(biāo)準(zhǔn)流的一些特性,記下來以供備忘。
                    首先是文件流,關(guān)于該流的問題,要扯就扯遠了,主要說一說std::wofstream的問題。不要被這個w騙了,其實它輸出到文件上的依然還是那么回事,沒有絲毫的變化。如果你是想輸出Unicode到文本文件中,那么你最好是用ios::binary模式,然后一股腦的倒入文件中,如果要是使用<<重載符號的話,輸出到文件中的跟std::ofstream沒區(qū)別,而且中文還無法輸出。如果你遇見中文無法輸出的問題,恩,可以調(diào)用std::wofstream::imbue()方法,具體也就是一行:ofs.imbue(std::locale("chs"));搞定。
            我想,C++標(biāo)準(zhǔn)庫并不支持Unicode編碼,而是給字符地域化的編碼方式,中文的可能也就是GBK吧,聽說C++0x標(biāo)準(zhǔn)會納入Unicode編碼支持,如果是這樣的話就省心多了。
                    然后還有個不省心的地方就是流的streambuf中的緩沖大小了,我發(fā)現(xiàn),fstream中的寫緩沖居然一直是0啊,這個就很頭疼了,需要給文件流指定緩沖的大小。

            posted @ 2009-07-29 23:46 釀妹汁 閱讀(1039) | 評論 (2)編輯 收藏

            DLL的共享測試

            今天稍微實驗了一下DLL的數(shù)據(jù)共享問題,做了兩種情況下的測試,第一種是兩個進程同時調(diào)用一個DLL的實驗,另一種是一個進程調(diào)用一個兩個DLL,然后這兩個DLL有依賴關(guān)系,記錄一下得到的測試結(jié)果。

            當(dāng)一個進程調(diào)用LoadLibrary、LoadLibraryEx以及FreeLibrary時,DllMain會被調(diào)用,從DllMain的入口函數(shù)的第二個參數(shù)可以得知是加載還是釋放。LoadLibraryEx的flag參數(shù)傳入DONT_RESOLVE_DLL_REFERENCES可以跳過DllMain的調(diào)用,這在很多時候是有用的。
            當(dāng)一個進程在調(diào)用LoadLibrary后又啟動了線程,則每啟動一個線程,就會調(diào)用一次DllMain,同樣可以從DllMain的第二個參數(shù)的值來區(qū)分調(diào)用時由進程引起的還是由線程引起的。第二個參數(shù)的值一般有4種,如下:
             DLL_PROCESS_ATTACH
             DLL_PROCESS_DETACH
             DLL_THREAD_ATTACH
             DLL_THREAD_DETACH
            不用解釋也能看得出來分別是表示什么意義了,通過這個可以選擇性的對DLL中的數(shù)據(jù)進行初始化。
            如果是兩個進程同時調(diào)用一個DLL的話,數(shù)據(jù)是不會共享的,除非你設(shè)置了seg項為共享,具體不同的編譯器會有不同的設(shè)置方法。兩個進程對同一個DLL的調(diào)用計數(shù)也是分開的,這讓我很放心了,之前一直害怕的沖突問題釋然。


            當(dāng)一個進程去調(diào)用一個DLL甲,而甲又在初始化的時候調(diào)用了DLL乙,進程通過甲的函數(shù)來訪問了DLL乙,同時自己也親自調(diào)用了DLL乙并取出和更改了數(shù)據(jù)。這樣的情況下,DLL乙的引用計數(shù)是共享的,數(shù)據(jù)也是共享的,加載和釋放都很安全,之前擔(dān)心DLL乙中的單件會被重復(fù)調(diào)用的情況也不可能存在了。

            posted @ 2009-06-27 23:04 釀妹汁 閱讀(577) | 評論 (0)編輯 收藏

            ASIO攻破?。?!

            花了足足3天時間,外加1天心情休整,終于在第5天編寫出了一個能運行的基于asio和thread_group的框架,差點沒氣暈過去,把源碼都看懂了才感覺會用了。
            測試了一下,debug下一萬次回應(yīng)耗時800+毫秒,release下是200+毫秒,機器配置雙核2.5G英特爾,4個線程并行工作,無錯的感覺真好,再也不用擔(dān)心iocp出一些奇怪的問題啦,因為是巨人們寫的實現(xiàn),呵呵。

            進入正題,簡要說一下asio的實現(xiàn)原理吧。在win32平臺上,asio是基于IOCP技術(shù)實現(xiàn)的,我以前也用過IOCP,卻沒想到居然能擴展成這樣,真是神奇!在其他平臺下還會有別的方法去實現(xiàn),具體見io_service類下面這部分的源碼:
              // The type of the platform-specific implementation.
            #if defined(BOOST_ASIO_HAS_IOCP)
              typedef detail::win_iocp_io_service impl_type;
              friend 
            class detail::win_iocp_overlapped_ptr;
            #elif defined(BOOST_ASIO_HAS_EPOLL)
              typedef detail::task_io_service
            <detail::epoll_reactor<false> > impl_type;
            #elif defined(BOOST_ASIO_HAS_KQUEUE)
              typedef detail::task_io_service
            <detail::kqueue_reactor<false> > impl_type;
            #elif defined(BOOST_ASIO_HAS_DEV_POLL)
              typedef detail::task_io_service
            <detail::dev_poll_reactor<false> > impl_type;
            #else
              typedef detail::task_io_service
            <detail::select_reactor<false> > impl_type;
            #endif
            這部分代碼其實就在boost::asio::io_service類聲明中的最前面幾行,可以看見在不同平臺下,io_service類的實現(xiàn)將會不同。很顯然,windows平臺下當(dāng)然是win_iocp_io_service類為實現(xiàn)了(不過我一開始還以為win_iocp_io_service是直接拿出來用的呢,還在疑惑這樣怎么有移植性呢?官方文檔也對該類只字不提,其實我卡殼就是卡在這里了,差點就直接用這個類了^_^!)。

            那么就分析一下win_iocp_io_service的代碼吧,這里完全是用IOCP來路由各種任務(wù),大家使用post來委托任務(wù),內(nèi)部調(diào)用的其實是IOCP的PostQueuedCompletionStatus函數(shù),然后線程們用run來接受任務(wù),內(nèi)部其實是阻塞在IOCP的GetQueuedCompletionStatus函數(shù)上,一旦有了任務(wù)就立即返回,執(zhí)行完后再一個循環(huán),繼續(xù)阻塞在這里等待下一個任務(wù)的到來,這種設(shè)計思想堪稱神奇,對線程、服務(wù)以及任務(wù)完全解耦,靈活度達到了如此高度,不愧為boost庫的東西!我只能有拜的份了...

            說一下總體的設(shè)計思想,其實io_service就像是勞工中介所,而一個線程就是一個勞工,而調(diào)用post的模塊相當(dāng)于富人們,他們?nèi)ブ薪樗腥蝿?wù),而勞工們就聽候中介所的調(diào)遣去執(zhí)行這些任務(wù),任務(wù)的內(nèi)容就寫在富人們給你的handler上,也就是函數(shù)指針,指針指向具體實現(xiàn)就是任務(wù)的實質(zhì)內(nèi)容。其實在整個過程中,富人們都不知道是哪個勞工幫他們做的工作,只知道是中介所負責(zé)完成這些就可以了。這使得邏輯上的耦合降到了最低。不過這樣的比喻也有個不恰當(dāng)?shù)牡胤?,如果硬要這樣比喻的話,我只能說:其實勞工里面也有很多富人的^o^! 。很多勞工在完成任務(wù)的過程中自己也托給中介所一些任務(wù),然后這些任務(wù)很可能還是自己去完成。這也難怪,運行代碼的總是這些線程,那么調(diào)用post的肯定也會有這些線程了,不過不管怎么說,如此循環(huán)往復(fù)可以解決問題就行,比喻不見得就得恰當(dāng),任何事物之間都不可能完全相同,只要能闡述思想就行。

            最后還要說明的一點就是:委托的任務(wù)其實可以設(shè)定執(zhí)行的時間的,很不錯的設(shè)定,內(nèi)部實現(xiàn)則是通過定時器原理,GetQueuedCompletionStatus有一個等待時間的參數(shù)似乎被用在這方面,還有源碼中的定時器線程我并沒有過多的去理解,總之大體原理已基本掌握,剩下的就是使勁的用它了?。。?br>
            另外為了方便人交流,在這里插入一些代碼可能更容易讓人理解吧,
            下面這個是啟動服務(wù)時的代碼:
            void ServerFramework::run()
            {
                boost::thread_group workers;
                
            for (uint32 i = 0; i < mWorkerCount; ++i)
                    workers.create_thread(
                        boost::bind(
            &boost::asio::io_service::run, &mIoService));
                workers.join_all();
            }

            在打開前就得分配好任務(wù),否則線程們運行起來就退出了,阻塞不住,任務(wù)的分配就交給open函數(shù)了,它是分配了監(jiān)聽端口的任務(wù),一旦有了連接就會拋出一個任務(wù),其中一個線程就會開始行動啦。
            void ServerFramework::open(const String& address, const String& port, uint32 nWorkers /*= DEFAULT_WORKER_COUNT*/)
            {
                
            // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
                boost::asio::ip::tcp::resolver resolver(mIoService);
                boost::asio::ip::tcp::resolver::query query(address, port);
                boost::asio::ip::tcp::endpoint endpoint 
            = *resolver.resolve(query);

                mAcceptor.open(endpoint.protocol());
                mAcceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(
            true));
                mAcceptor.bind(endpoint);
                mAcceptor.listen();

                mNextConnection 
            = new Connection(this);
                mAcceptor.async_accept(mNextConnection
            ->getSocket(),
                    boost::bind(
            &ServerFramework::__onConnect, this,
                    boost::asio::placeholders::error));

                mWorkerCount 
            = nWorkers;
                
            if (mWorkerCount == DEFAULT_WORKER_COUNT)
                
            {
                    mWorkerCount 
            = 4;
                }

            }

            open函數(shù)中給io_service的一個任務(wù)就是在有鏈接訪問服務(wù)器端口的情況下執(zhí)行ServerFramework::__onConnect函數(shù),有一點需要格外注意的,io_service必須時刻都有任務(wù)存在,否則線程io_service::run函數(shù)將返回,于是線程都會結(jié)束并銷毀,程序?qū)⑼顺?,所以,你必須保證無論何時都有任務(wù)存在,這樣線程們即使空閑了也還是會繼續(xù)等待,不會銷毀。所以,我在ServerFramework::__onConnect函數(shù)中又一次給了io_service相同的任務(wù),即:繼續(xù)監(jiān)聽端口,有鏈接了還是調(diào)用ServerFramework::__onConnect函數(shù)。如果你在ServerFramework::__onConnect執(zhí)行完了還沒有給io_service任務(wù)的話,那么一切都晚了...... 代碼如下:
            void ServerFramework::__onConnect(const BoostSysErr& e)
            {
                
            if (e)
                
            {
                    MOELOG_DETAIL_WARN(e.message().c_str());
                }


                Connection
            * p = mNextConnection;
                mNextConnection 
            = new Connection(this);

                
            // 再次進入監(jiān)聽狀態(tài)
                mAcceptor.async_accept(mNextConnection->getSocket(),
                    boost::bind(
            &ServerFramework::__onConnect, this,
                    boost::asio::placeholders::error));

                
            // 處理當(dāng)前鏈接
                __addConnection(p);
                p
            ->start();
            }

            最后,展示一下這個類的所有成員變量吧:
                // 用于線程池異步處理的核心對象
                boost::asio::io_service mIoService;

                
            // 網(wǎng)絡(luò)鏈接的接收器,用于接收請求進入的鏈接
                boost::asio::ip::tcp::acceptor mAcceptor;

                
            // 指向下一個將要被使用的鏈接對象
                Connection* mNextConnection;

                
            // 存儲服務(wù)器鏈接對象的容器
                ConnectionSet mConnections;

                
            //// 為鏈接對象容器準(zhǔn)備的strand,防止并行調(diào)用mConnections
                //boost::asio::io_service::strand mStrand_mConnections;

                
            // 為鏈接對象容器準(zhǔn)備的同步鎖,防止并行調(diào)用mConnections
                boost::mutex mMutex4ConnSet;

                
            // 為控制臺輸出流準(zhǔn)備的strand,防止并行調(diào)用std::cout
                AsioService::strand mStrand_ConsoleIostream;

                
            // 工作線程的數(shù)量
                uint32 mWorkerCount;



            但愿這篇隨筆也能對正在研究asio的朋友們有所幫助吧。

            posted @ 2009-06-26 22:14 釀妹汁 閱讀(9927) | 評論 (15)編輯 收藏

            MySQL的備忘錄

            首先安裝完MySQL5.1.30后,可以進入控制臺,輸入 mysql -u root -p然后回車,如果沒有密碼的話,-p似乎就能省掉了。
            進入后輸入 show databases命令就可以看到所有的數(shù)據(jù)庫了。
            然后是新用戶的問題,如果你想添加一個新的用戶,有很下列三種方法:
            1、直接在mysql數(shù)據(jù)庫中的user表里直接insert,但是很麻煩
            2、使用GRANT [權(quán)限] ON *.* TO [username]@[客戶端地址] identified by [password]  這樣的命令,具體可以看文檔
            3、使用CREATE USER [用戶名] 這樣的命令創(chuàng)建用戶
            這里要注意的是,第二種方法創(chuàng)建用戶的話,必須帶有密碼,如果你想創(chuàng)建無密碼用戶的話,則必須用第3種方法。
            最后就是給用戶權(quán)限的問題,一般都使用GRANT語句,具體可參考文檔,不過你也可以直接對db表直接進行修改和添加,只要你不怕麻煩。

            posted @ 2009-06-26 21:30 釀妹汁 閱讀(219) | 評論 (0)編輯 收藏

            僅列出標(biāo)題
            共3頁: 1 2 3 
            日产精品久久久久久久| 久久久亚洲AV波多野结衣| 久久男人Av资源网站无码软件 | 久久精品国产清高在天天线| 亚洲国产成人乱码精品女人久久久不卡 | 久久亚洲电影| 国产成人精品综合久久久久| 久久久久一区二区三区| 久久久久亚洲AV成人片| 国产国产成人精品久久| 久久青青草原精品国产| 好久久免费视频高清| 国产99久久久久久免费看| 欧美日韩中文字幕久久久不卡 | 久久人人爽人爽人人爽av| 久久亚洲高清综合| 久久久久无码精品国产| 蜜桃麻豆www久久| 久久久久亚洲精品日久生情 | 99久久久国产精品免费无卡顿| 久久久久高潮毛片免费全部播放| 久久99国产综合精品| 久久精品国产亚洲av日韩| 久久99精品久久久久久久久久| 国内精品久久久久影院免费| 91精品国产91久久| 麻豆av久久av盛宴av| 久久精品国产久精国产| 久久综合九色综合久99| 久久精品一本到99热免费| 精品无码人妻久久久久久| 亚洲va久久久噜噜噜久久狠狠| 国产精品亚洲美女久久久| 狠狠88综合久久久久综合网| 91精品国产91久久久久福利| 亚洲狠狠综合久久| 热re99久久精品国产99热| 亚洲AV无码久久精品色欲| 久久久久久毛片免费看| 狠狠狠色丁香婷婷综合久久俺| 国内精品久久久久影院薰衣草 |