• <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>

            那誰的技術博客

            感興趣領域:高性能服務器編程,存儲,算法,Linux內核
            隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
            數據加載中……

            服務器定時器處理要注意的問題

            今天早上,例行巡查服務器,我用strace命令跟蹤服務器進程的時候, 發現有幾個服務器進程出現了死鎖情況, gdb繼續跟進,顯示如下:

            gdb) bt
            #
            0  0x00ff9410 in __kernel_vsyscall ()
            #
            1  0x004d593e in __lll_mutex_lock_wait () from /lib/libc.so.6
            #
            2  0x00465b38 in _L_lock_14080 () from /lib/libc.so.6
            #
            3  0x00464df4 in free () from /lib/libc.so.6
            #
            4  0x006c7691 in operator delete () from /usr/lib/libstdc++.so.6
            #
            5  0x08059cfb in __gnu_cxx::new_allocator<std::_List_node<TTimeEvent> >::deallocate (this=0x98e0064, __p=0x98e1218)
                at 
            /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/ext/new_allocator.h:94
            #
            6  0x08059d20 in std::_List_base<TTimeEvent, std::allocator<TTimeEvent> >::_M_put_node (this=0x98e0064, __p=0x98e1218)
                at 
            /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_list.h:320
            #
            7  0x08059d81 in std::list<TTimeEvent, std::allocator<TTimeEvent> >::_M_erase (this=0x98e0064, __position=
                  {_M_node 
            = 0x98e1218}) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_list.h:1150
            #
            8  0x08059db3 in std::list<TTimeEvent, std::allocator<TTimeEvent> >::pop_front (this=0x98e0064)
                at 
            /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_list.h:747
            #
            9  0x08059334 in CTimerManager::Process (this=0x98e0058) at src/timermanager.cpp:168
            #
            10 0x080597dd in Process (nSigNo=14) at src/timermanager.cpp:199
            #
            11 <signal handler called>
            #
            12 0x004612ba in _int_free () from /lib/libc.so.6
            #
            13 0x00464e00 in free () from /lib/libc.so.6
            #
            14 0x006c7691 in operator delete () from /usr/lib/libstdc++.so.6
            #
            15 0x006a424d in std::string::_Rep::_M_destroy () from /usr/lib/libstdc++.so.6
            #
            16 0x0069e40f in std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf ()
               from 
            /usr/lib/libstdc++.so.6
            #
            17 0x0069fd7f in std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::~basic_stringstream ()
               from 
            /usr/lib/libstdc++.so.6
            #
            18 0x080524ea in CDBMoudle::Insert (this=0x98e6e80, tFixkey=@0xbfe1c6ec) at src/dbmoudle.cpp:59
            #
            19 0x08051718 in CConnectionTask::ProcFixContent (this=0x98e6510) at src/connectiontask.cpp:218
            #
            20 0x0805196e in CConnectionTask::HandleRead (this=0x98e6510) at src/connectiontask.cpp:86
            #
            21 0x08051a0f in CConnectionTask::Handle (this=0x98e6510, nEvent=1) at src/connectiontask.cpp:52
            #
            22 0x080585af in IServer::Run (this=0xbfe1c7e0) at src/server.cpp:133
            #
            23 0x08055328 in main (argc=2, argv=0xbfe1c8b4) at src/main.cpp:19
            在#13處,調用free函數, 然后進入與之相關的libc函數調用中.但是, 在這個調用還沒有完結之前被定時器管理模塊中斷, 進入了定時器處理的部分, 在在這個處理中同樣調用了free函數, 于是出現了死鎖的情況--因為malloc/free函數族不是可重入的, 在這里有一篇相關的文章.

            我曾經想在我的服務器代碼中盡量減少對象的構造/析構, 但是想了一下, 這個策略不是治本的辦法, 這意味著我必須在寫代碼的時候處處小心, 今天可能在A處出現死鎖, 明天可能會在B處出現.而且, 由于使用的是C++, 一些局部對象的構造和析構是不可避免的.

            于是, 解決這個問題的思路就改變為:盡量的簡單化定時器處理操作.目前我想到的一個策略時, 一個定時器被觸發的時候, 置一個標志位, 而不是在在觸發的時候調用相應的處理函數, 然后在服務器的主循環中判斷是否被置位, 如果是的話再去調用相關的處理函數.

            于是, 原來的思路就是:
            // 該函數在定時器到時的時候被觸發
            void signal()
            {
               
            // 定時器處理函數
               dosomething();
            }

            while(1)
            {
               服務器主循環;
            }

            修改之后的思路是:
            int violate g_alarm = 0;

            // 該函數在定時器到時的時候被觸發
            void signal()
            {
              g_alarm 
            = 1;
            }

            while(1)
            {
               服務器主循環;
               
            if (g_alarm)
               {
                   
            // 定時器處理函數
                  dosomething();
                  g_alarm 
            = 0;
               }
            }


            這是大概的模型上面的改變.這是我目前能想到的處理該問題的最好辦法, 如果哪位有更好的辦法歡迎補充.


            posted on 2008-10-16 19:08 那誰 閱讀(5071) 評論(10)  編輯 收藏 引用 所屬分類: 服務器設計 、Linux/Unix

            評論

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            認同你的做法
            這種做法很常見,簡單實用
            2008-10-16 21:49 | LOGOS

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            內存池
            2008-10-17 12:46 | kevin

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            我覺得定時器只負責產生消息即可。
            2008-10-17 13:23 | lihui

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            是不是要加鎖?小弟不才,請指教.
            while & signal 都修改了這個violate,所以考慮要不要加鎖?
            2008-10-20 08:39 | ocean

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            明白了,不加鎖,呵呵,讀你的東西真是受用.
            2008-10-20 08:42 | ocean

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            這樣的做法 很簡單,但是很難看。

            效率高一些,卻不優雅。 擴展比較難。

            如果多一些事件的話,可能把主線程搞成非常亂
            2009-04-24 17:26 | 妞妞

            # re: 服務器定時器處理要注意的問題[未登錄]  回復  更多評論   

            @妞妞
            那有什么好的建議沒有呢?
            2009-04-27 17:07 | 那誰

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            建議看看libevent的定時器實現。
            很優美的實現。將IO,信號和定時器都作為事件來統一進行分發。
            2009-12-26 05:35 | 浩毛

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            假設現在g_alarm = 1,進入了if中正在處理do_something,恰好現在產生一個信號使 g_alarm = 1,當do_something退出時, g_alarm = 0了,所以丟失了一個信號事件。這個問題該怎么辦?
            2011-01-15 10:18 | xunuj

            # re: 服務器定時器處理要注意的問題  回復  更多評論   

            剛從博主《libevent 事件處理框架分析》中看到
            “信號事件:所有的信號都注冊回調函數為evsignal_handler(在signal.c中),這個函數的功能就是在某信號被觸發的時候將該信號被觸發的計數器加1,同時置一個標志位表示有信號被觸發.“
            2011-01-15 10:34 | xunuj
            香蕉久久永久视频| 久久综合久久综合九色| 久久久这里只有精品加勒比| 伊人久久大香线蕉精品不卡| 五月丁香综合激情六月久久| 国产精品久久国产精品99盘 | 国产午夜精品久久久久免费视| 久久国产欧美日韩精品| 国产99久久久国产精品~~牛| 久久伊人影视| 久久精品无码一区二区无码| 欧美精品福利视频一区二区三区久久久精品 | 色婷婷综合久久久中文字幕| 亚洲一区中文字幕久久| 无码人妻久久久一区二区三区| 99久久婷婷国产综合精品草原| 欧美牲交A欧牲交aⅴ久久| 精品国产一区二区三区久久蜜臀| 色欲久久久天天天综合网| 热综合一本伊人久久精品| 久久―日本道色综合久久| 无码伊人66久久大杳蕉网站谷歌| 久久精品视频一| 精品久久久久久无码国产| 99久久久精品| 久久精品国产第一区二区三区| 亚洲精品NV久久久久久久久久 | 精品人妻伦一二三区久久| 国产精品久久午夜夜伦鲁鲁| 无码精品久久久久久人妻中字 | 久久精品国产亚洲AV香蕉| 久久精品无码一区二区三区日韩| 国产精品视频久久| 久久电影网一区| 国产精品久久久久9999| 久久久久久午夜成人影院| 久久人妻少妇嫩草AV无码专区| 久久天天躁狠狠躁夜夜躁2014| 久久婷婷国产剧情内射白浆| 久久精品国产99久久久古代| 国产69精品久久久久久人妻精品|