sugar 发表于 2010-3-29 14:15:43

ACE日志策略出现的crash问题

ACE的日志策略中没有按天分割的方法(有按文件大小的方法),我自己用reactor+实时器实现了一个:
在每天的零点, 定时器到期:
以下是handle_timeout方法:

int CXXXXTimer::handle_timeout(const ACE_Time_Value &current_time,
         const void *act /* = 0 */)
{
int nRet = 0;
init_log_config();
return nRet;
}

int init_log_config()
{
if (ACE_LOG_MSG->acquire())
return -1;
ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM);
// 先保存先前的输出
ACE_OSTREAM_TYPE *old_output = ACE_LOG_MSG->msg_ostream();
// 日志文件名
std::string strLogFilePath;
CUtility::GetAppPath(strLogFilePath);
std::string strDay = CUtility::get_current_day(); // CUtility::get_current_day()返回类似于这样的字符串:2010-03-29
strLogFilePath += strDay;
strLogFilePath += ".log";

ACE_OSTREAM_TYPE *output = new std::ofstream (strLogFilePath.c_str(),std::ios_base::out | std::ios_base::app);
ACE_LOG_MSG->msg_ostream (output, 1);
ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);

if (old_output)
{
#if defined (ACE_LACKS_IOSTREAM_TOTALLY)
FILE *output_file = (FILE *)old_output;
ACE_OS::fclose (output_file);
#else
ofstream *output_file = (ofstream *)old_output;
output_file->close ();
#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
delete old_output;
old_output = 0;
}
ACE_LOG_MSG->release();
return 0;
}

现在的问题是: 第当定时器当期: handle_timeout方法执行后, 能生成一个正确的文件名,如今天的日志文件名为2010-02-29.log,到了2010-03-30的零点就会生成名称为2010-03-30.log的日志文件. 此后的一调用ACE_DEBUG就会crash掉.
堆栈如下:
(1)ACEd.dll!std::basic_ostream<char,std::char_traits<char> >::_Sentry_base::_Sentry_base(std::basic_ostream<char,std::char_traits<char> > & _Ostr={...})行81 + 0x28 字节 C++
(2)ACEd.dll!std::basic_ostream<char,std::char_traits<char> >::sentry::sentry(std::basic_ostream<char,std::char_traits<char> > & _Ostr={...})行99 + 0x3a 字节 C++
(3)ACEd.dll!std::operator<<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> > & _Ostr={...}, const char * _Val=0x09f7ac38)行751 + 0xc 字节 C++
(4)ACEd.dll!ACE_Log_Record::print(const char * host_name=0x00000000, unsigned long verbose_flag=5, std::basic_ostream<char,std::char_traits<char> > & s={...})行399 + 0xd 字节 C++
(5)ACEd.dll!ACE_Log_Msg::log(ACE_Log_Record & log_record={...}, int suppress_stderr=0)行2220 C++
(6)ACEd.dll!ACE_Log_Msg::log(const char * format_str=0x004fe487, ACE_Log_Priority log_priority=LM_DEBUG, char * argp=0x0667d934)行2069 + 0x11 字节 C++
(7)ACEd.dll!ACE_Log_Msg::log(ACE_Log_Priority log_priority=LM_DEBUG, const char * format_str=0x004fe440, ...)行953 + 0x14 字节 C++
(8)XXX.exe!XXX_Progress(const char * package=0x0667dc88, std::basic_string<char,std::char_traits<char>,std::allocator<char> > & result="", HLL_COMM_TYPE::InterfaceType ift=IFT_CLIENT)行37 + 0xea 字节 C++
.................

上面的(1)对应的源代码为:ostream中的(标记为红色)
__CLR_OR_THIS_CALL _Sentry_base(_Myt& _Ostr)
   : _Myostr(_Ostr)
   { // lock the stream buffer, if there
   if (_Myostr.rdbuf() != 0)
    _Myostr.rdbuf()->_Lock();   // 这里是ostream中的81行
   }

上面的(2)对应的源代码为:ostream中的(标记为红色)
explicit __CLR_OR_THIS_CALL sentry(_Myt& _Ostr)
: _Sentry_base(_Ostr)       // 这里是ostream中的98行
   { // construct locking and testing stream
   if (_Ostr.good() && _Ostr.tie() != 0)
    _Ostr.tie()->flush();
   _Ok = _Ostr.good(); // store test only after flushing tie
   }

我想可能前后两个输出流死锁(具体什么原因我也搞不清). 不知道有没有遇过个这个问题. 另外ACE_DEBUG在多个线程中调用.

此外我也注意到另一个帖子:
http://www.acejoy.com/bbs/viewthread.php?tid=944&extra=page%3D1
以及:
http://www.cppblog.com/elva/archive/2008/07/31/57534.html

如果实现无法解决,只好换用其它方法来实现输出到日志了.

谢谢大家!!!

sugar 发表于 2010-3-29 14:41:16

dump信息.

dump文件如下:

This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(1840.2aa0): Access violation - code c0000005 (first/second chance not available)
eax=00000000 ebx=00000000 ecx=aff0cf00 edx=09c47341 esi=00a4b920 edi=0000008c
eip=10035828 esp=1080caac ebp=1080cadc iopl=0         nv up ei pl nz na po nc
cs=001bss=0023ds=0023es=0023fs=003bgs=0000             efl=00010202
ACE!std::operator<<<std::char_traits<char> >+0x48:
10035828 8b4804          mov   ecx,dword ptr ds:0023:00000004=????????

wishel 发表于 2010-3-29 16:16:39

这个问题我到现在也没有搞定。
上次和freeeyes一起调了一下,他那边是winxp很难重现,我这边是vista重现崩溃比较容易。
最后没找到具体原因。

sugar 发表于 2010-3-29 16:24:00

是啊,非常难搞.
我这种方式每次都会重现.

winston 发表于 2010-3-29 21:40:03

每次都重现的,应该好调试的。
你贴的那个文章,我很早看过。
我觉得应该是线程同步导致的,你尝试修改一下,加一下线程同步操作。

steven99ca 发表于 2010-4-2 05:13:41

可能是内部的stream对象不对。
重载handle_timeout,
或在你的handle_timeout里调用它的handle_timeout.
可以发现问题。
页: [1]
查看完整版本: ACE日志策略出现的crash问题