slugzoe 发表于 2009-11-25 10:15:39

一个ACE中getq()时候产生的问题

在我的网络程序中,getq()会在数据传输量很大的时候出现segmentation fault,Call Stack如下
#00x001d7526 in ACE_Message_Block::total_size_and_length (this=0xb7fc93a8, mb_size=@0xb5ac5f8c, mb_length=@0xb5ac5f88) at Message_Block.cpp:267
#10x080507a9 in ACE_Message_Queue <ACE_MT_SYNCH>::dequeue_head_i (this=0x9794dd0, first_item=@0xb5ac6040) at ../../../../usr/local/ACE_wrappers/ace/Message_Queue_T.cpp:1334
#20x08053e74 in ACE_Message_Queue <ACE_MT_SYNCH>::dequeue_head (this=0x9794dd0, first_item=@0xb5ac6040, timeout=0xb5ac6038)
    at ../../../../usr/local/ACE_wrappers/ace/Message_Queue_T.cpp:1786
#30x08057d4a in ACE_Task <ACE_MT_SYNCH>::getq (this=0x9794d50, mb=@0xb5ac6040, tv=0xb5ac6038) at ../../../../usr/local/ACE_wrappers/ace/Task_T.inl:24
#40x08056e6c in GateWayService::handle_output (this=0x9794d50, hdl=17) at /home/bigboss/codeblocks_workspace/gateway_server/src/client_connection.cpp:207
#50x001a807d in ACE_Select_Reactor_T <ACE_Reactor_Token_T <ACE_Token> >::notify_handle (this=0x9787938, handle=17, mask=2, ready_mask=@0x9787ecc, event_handler=0x9794d50,
    ptmf= <error reading variable>) at /usr/local/ACE_wrappers/ace/Select_Reactor_T.cpp:817
#60x001a738d in ACE_Select_Reactor_T <ACE_Reactor_Token_T <ACE_Token> >::dispatch_io_set (this=0x9787938, number_of_active_handles=4, number_of_handlers_dispatched=@0xb5ac6178,
    mask=2, dispatch_mask=@0x97879e0, ready_mask=@0x9787ecc, callback= <error reading variable>) at /usr/local/ACE_wrappers/ace/Select_Reactor_T.cpp:1205
#70x001a1409 in ACE_Select_Reactor_T <ACE_Reactor_Token_T <ACE_Token> >::dispatch_io_handlers (this=0x9787938, dispatch_set=@0x9787954, number_of_active_handles=@0xb5ac6194,
    number_of_handlers_dispatched=@0xb5ac6178) at /usr/local/ACE_wrappers/ace/Select_Reactor_T.cpp:1239
#80x001a19a2 in ACE_Select_Reactor_T <ACE_Reactor_Token_T <ACE_Token> >::dispatch (this=0x9787938, active_handle_count=4, dispatch_set=@0x9787954)
    at /usr/local/ACE_wrappers/ace/Select_Reactor_T.cpp:1367
#90x001a6ac3 in ACE_Select_Reactor_T <ACE_Reactor_Token_T <ACE_Token> >::handle_events (this=0x9787938, max_wait_time=0x0) at /usr/local/ACE_wrappers/ace/Select_Reactor_T.cpp:1447
#10 0x001fdc83 in ACE_Reactor::handle_events (this=0x9783738, max_wait_time=0x0) at Reactor.cpp:420
#11 0x0804ba0f in updateServer4Logic (argv=0x0) at /home/bigboss/codeblocks_workspace/gateway_server/main.cpp:88
#12 0x001e3b67 in ACE_OS_Thread_Adapter::invoke (this=0x9783800) at OS_Thread_Adapter.cpp:90
#13 0x001a95d1 in ace_thread_adapter (args=0x9783800) at Base_Thread_Adapter.cpp:116
#14 0x00c9850b in start_thread () from /lib/libpthread.so.0
#15 0x00bd9b2e in clone () from /lib/libc.so.6
出错是在
0x001d7526 in ACE_Message_Block::total_size_and_length (this=0xb7fc93a8, mb_size=@0xb5ac5f8c, mb_length=@0xb5ac5f88) at Message_Block.cpp:267
267          mb_size += i->size ();
这句,我怀疑可能是msg_queue_线程不安全,所以我将
class GateWayService : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH >
改为了
class GateWayService : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_MT_SYNCH >
可是程序依旧出错,哪位前辈能指点下问题还可能出在哪儿吗?如果需要更多信息,请说明

shenming 发表于 2009-11-25 12:40:25

对getq的认识

getq只是dequeue_head_i的一个包装,对ACE_Message_Queue 来说是安全的,不会有任何问题,而且,ACE_Message_Queue 是非常健壮的,它唯一的缺陷就是有微乎其微的内部锁开销,其它没有任何问题。我想你的错误应该不在这里,而且堆栈跟踪也不是非常准确的,只能说在附近,尤其是多线程程序更是如此。

从你打出来的信息暂时看不出错误所在。是不是其它线程已经将队列删除了。多线程编程经常会出这种错。 呵呵。

slugzoe 发表于 2009-11-25 13:23:02

其实整个程序只有在这里会对msg_queue_进行操作,没有其他地方对其操作,想不通为什么.定位不准确的确我也考虑过,但是这个bug是几乎可以100%重现的,每次的call stack都是这样.所以我比较相信了就~

slugzoe 发表于 2009-11-25 15:48:33

这里贴出出问题处的函数:
int GateWayService::handle_output( ACE_HANDLE hdl )
{
    while( msg_queue_->is_empty()==0 ) {
      ACE_Message_Block* mb;
      ACE_Time_Value nowait( ACE_OS::gettimeofday() );
      ACE_SEH_TRY {
            getq( mb, &nowait );
      }
      ACE_SEH_EXCEPT ( EXCEPTION_EXECUTE_HANDLER){
            continue;
      }

      ACE_UINT32 left = send_dp_->capacity() - send_dp_->length();
      if( mb->length() > left ) {
            ACE_UINT8* buf;
            ACE_UINT32 bufSz = send_dp_->p_pack( buf );
            ACE_DEBUG ( ( LM_DEBUG, ACE_TEXT ( "line[%d] %s SEND Data to Client: bufSz = %d\n" ),
                                                                            __LINE__, __FUNCTION__, bufSz ) );
            ssize_t send_cnt = this->peer().send( buf, bufSz );
             if( send_cnt == -1 ) {
               ACE_ERROR((LM_ERROR,ACE_TEXT("(%P|%t)%p\n"),ACE_TEXT("send")));
               return -1;
             }
             send_dp_->release();
             send_dp_ = DataPackage::create( 1 );
      }
      send_dp_->append( ( ACE_UINT8* )mb->rd_ptr(), mb->length() );
      ACE_ERROR((LM_ERROR,ACE_TEXT("mb->rd_ptr()=%d mb->length()=%d\n"),*( ACE_UINT8* )mb->rd_ptr(),mb->length()));
      mb->release();
   }
    return 0;
}

wishel 发表于 2009-11-25 15:55:59

多线程的调试是很痛苦的。
我也正在调一个多线程的程序,问题很难重现,如果能找到必然重现的办法差不多也就找到原因了。痛苦啊。

slugzoe 发表于 2009-11-25 16:46:36

我这个程序实际上是单线程的=.=回头来看了看,其实只是对象不同,线程只有一个....那那个bug就更让人费解了

modern 发表于 2009-11-25 17:21:22

首先,楼主使用ACE_MT_SYNCH初始化ACE_Svc_Handler是有必要的。
ACE_Svc_Handler的第二个模版参数会直接影响到ACE_Message_Queue的初始化使用的模版参数,
如果是用ACE_NULL_SYNCH初始化,那么ACE_Message_Queue就不是线程安全的。
其次,通过楼主的贴出来的代码,也没看出来什么问题,再多贴些代码出来吧。

slugzoe 发表于 2009-11-25 23:42:05

这里想问个问题,handle_output()和handle_timeout()是同一个线程还是不同的线程呢?

modern 发表于 2009-11-26 09:18:48

看你Reactor使用的什么实现,
如果使用Select_Reactor是单线程的运行的,不需要线程保护机制。
如果使用线程池运行Reactor,比如TP_Reactor
同一对象的handle_output与handle_timeout会同时在不同的线程里被调用。

wishel 发表于 2009-11-26 14:18:32

void
ACE_Message_Block::total_size_and_length (size_t &mb_size,
                                          size_t &mb_length) const
{
ACE_TRACE ("ACE_Message_Block::total_size_and_length");

for (const ACE_Message_Block *i = this;
       i != 0;
       i = i->cont ())
    {
      mb_size += i->size ();
      mb_length += i->length ();
    }
}

无法继续跟进到size ()里去了么?如果这样那就是i的问题了。i不是0,但又不是指向一个有效的message block。能确保最初拼接复合message block的时候没问题么?
页: [1] 2 3
查看完整版本: 一个ACE中getq()时候产生的问题