• <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 那誰 閱讀(5072) 評論(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国产精品一区二区| 久久久久久久综合日本| 久久综合狠狠综合久久97色| 国产精品久久婷婷六月丁香| 久久久久久毛片免费播放| 久久综合九色综合精品| 日本加勒比久久精品| 蜜臀av性久久久久蜜臀aⅴ麻豆| 国内精品伊人久久久久影院对白| 综合久久国产九一剧情麻豆| 88久久精品无码一区二区毛片| 亚洲国产成人久久笫一页| 国产精品久久久久国产A级| 波多野结衣久久一区二区| 日本福利片国产午夜久久| 色88久久久久高潮综合影院| 精品国产91久久久久久久a| 国产成年无码久久久久毛片| 久久亚洲熟女cc98cm| 久久九九久精品国产| 91超碰碰碰碰久久久久久综合| 久久综合噜噜激激的五月天| 久久精品国产男包| 日本久久中文字幕| 久久人人爽人人精品视频| 伊人丁香狠狠色综合久久| 国产美女久久久| av无码久久久久久不卡网站| 亚洲AV无码1区2区久久| 久久久久久久精品成人热色戒| 久久久久97国产精华液好用吗| 国产精品九九久久免费视频 | 亚洲国产另类久久久精品黑人| 久久e热在这里只有国产中文精品99 | 久久精品成人欧美大片| 亚洲精品无码久久毛片| 一本综合久久国产二区| 欧美精品乱码99久久蜜桃| 久久中文字幕精品| 综合网日日天干夜夜久久|