找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 5000|回复: 7

多线程下ACE_LOG析构异常问题

[复制链接]
发表于 2010-7-16 09:28:37 | 显示全部楼层 |阅读模式
本帖最后由 dwh0403 于 2010-7-16 09:38 编辑

测试多线程日志的问题,ACE5.7.9 + WIN7 + VS2005
测试代码:
  1. int ACE_TMAIN(int argc, ACE_TCHAR *argv[])
  2. {
  3. int thread_num = 10;
  4. int flag = THR_NEW_LWP | THR_DETACHED |  THR_INHERIT_SCHED; // 我故意设置成THR_DETACHED的
  5. CTestLogThread task;
  6. task.open(thread_num, flag);
  7. ACE_OS::sleep(5);
  8. ACE_Thread_Manager::instance()->cancel_all();
  9. ACE_Thread_Manager::instance()->wait();
  10. return 0;
  11. }
  12. class CTestLogThread: public ACE_Task<ACE_NULL_SYNCH>
  13. {
  14. public:
  15.   int open(int thread_num = 1, int thread_flag = THR_NEW_LWP | THR_INHERIT_SCHED);
  16.   virtual int svc (void);
  17. };
  18. int CTestLogThread: open(int thread_num, int thread_flag)
  19. {
  20. // Create worker threads.
  21. if (this->activate (thread_flag, thread_num) == -1)
  22.   ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("activate failed")), -1);
  23. return 0;
  24. }
  25. int CTestLogThread::svc()
  26. {
  27. ACE_LOG_MSG->enable_debug_messages();
  28. for (int i = 0; i < 1000000; i++)
  29. {
  30.   if (ACE_Thread_Manager::instance()->testcancel(ACE_OS::thr_self()))
  31.   {
  32.    ACE_DEBUG((LM_DEBUG, "(%t) cancelled by manager\n"));
  33.    return 0;
  34.   }
  35.   ACE_DEBUG((LM_DEBUG, ACE_TEXT("[url=mailto:%D@(%t)@@[%d]\n]%D@(%t)@@[%d]\n[/url]"), i));
  36. }
  37. return 0;
  38. }
复制代码
测试过程中会偶尔出现程序非法关闭,问题在于
  1. ACE_Log_Msg::~ACE_Log_Msg (void)函数中的
  2. {
  3.   .........
  4.   {
  5.     ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
  6.                        *ACE_Log_Msg_Manager::get_lock ()));
  7.     instance_count = --instance_count_;
  8.   }
  9.   
  10.   // If this is the last instance then cleanup.  Only the last
  11.   // thread to destroy its ACE_Log_Msg instance should execute
  12.   // this block.
  13.   if (instance_count == 0) // 调试代码显示代码到了此处,但是在此以后才调用了  (也可能为调试器显示有误)  
  14. // ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,*ACE_Log_Msg_Manager::get_lock ()));   的释放函数
  15. {
  16.       // Destroy the message queue instance.
  17.       if (ACE_Log_Msg_Manager::log_backend_ != 0)
  18.         ACE_Log_Msg_Manager::log_backend_->close ();
  19.      ...................
  20. }
复制代码
释放该ACE_Recursive_Thread_Mutex时候出现异常,最终调用的为调用ACE_OS::thread_mutex_unlock (m);时候m为无效的指针。

该问题很难重现,一般要手工实验很多次才会出现一次,哪位有没有碰到过这种问题,有什么好的建议没有?
发表于 2010-7-16 11:25:55 | 显示全部楼层
以前记得有人发现过这个问题,好像是个bug,你搜索一下论坛找找。
发表于 2010-7-21 09:48:34 | 显示全部楼层
析构的时的崩溃时发生的哪个线程?
主线程还是工作线程?
印象里ACE_Log_Msg是一个线程一个实例。
贴一些更为详细的信息出来,比如堆栈,线程等
发表于 2010-7-21 10:01:03 | 显示全部楼层
感觉可能被双删除引起的BUG,我以前也遇到过类似的问题。
在多线程调用下,引用计数器可能会出现判断错误。
你开了一个10个线程的线程池,是否可以尝试在svc里面增加一个ACE_Recursive_Thread_Mutex锁,即
ACE_Recursive_Thread_Mutex m_ThreadWriteLock

m_ThreadWriteLock.acquire();
。。。//这里是你的ACE_Log_Msg操作
m_ThreadWriteLock.release();
 楼主| 发表于 2010-7-21 14:46:22 | 显示全部楼层
析构的时候,错误显示的是工作线程,准确说最后一个工作线程析构的时候。这个问题比较难重现,出现概率不等。最近在ACE Bug列表中看到ACE_TSS好像存在问题,不知道是否是这个问题引起的,ACE TSS的bug见http://bugzilla.dre.vanderbilt.edu/show_bug.cgi?id=3539
 楼主| 发表于 2010-7-21 14:47:30 | 显示全部楼层
感觉可能被双删除引起的BUG,我以前也遇到过类似的问题。
在多线程调用下,引用计数器可能会出现判断错误。 ...
freeeyes 发表于 2010-7-21 10:01

LOG MSG对象写入文件的时候,会自动调用加锁操作。
 楼主| 发表于 2010-7-21 14:51:08 | 显示全部楼层
前几天看仔细看过 Singleton模式线程安全的实现,貌似ACE Double-Check Singleton也未必是线程安全的,很多问题也可能是这些地方导致的,只是举个例子。
 楼主| 发表于 2010-7-21 14:51:26 | 显示全部楼层
前几天看仔细看过 Singleton模式线程安全的实现,貌似ACE Double-Check Singleton也未必是线程安全的,很多问题也可能是这些地方导致的,只是举个例子。
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-11-22 07:43 , Processed in 0.014179 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表