[ace-users] Possible bug in ACE_Task_Base::cleanup.

Johnny Willemsen jwillemsen at remedy.nl
Wed Jul 11 15:33:33 CDT 2007


Hi,

Thanks for using the PRF form. The thread exits when svc returns, so the
thread count could be correct. Before exiting main you should wait until all
threads have finished.

Regards,

Johnny Willemsen
Remedy IT
Postbus 101
2650 AC  Berkel en Rodenrijs
The Netherlands
www.theaceorb.nl / www.remedy.nl  

*** Integrated compile and test statistics see
http://scoreboard.theaceorb.nl ***
*** Commercial service and support for ACE/TAO/CIAO             ***
*** See http://www.theaceorb.nl/en/support.html                 ***

"Krivenok Dmitry" <krivenok.dmitry at gmail.com> wrote in message
news:<1184179813.151737.56650 at g4g2000hsf.googlegroups.com>...
>     ACE VERSION: 5.5.8
> 
>     HOST MACHINE and OPERATING SYSTEM:
>     1) Machine : AMD Athlon 64 3500+, 512Mb RAM
>     2) OS: Gentoo Linux
>     Kernel : 2.6.20
>     Glibc  : 2.5-r3
> 
>     COMPILER NAME AND VERSION (AND PATCHLEVEL):
>     olimpico ~ # gcc --version
>     gcc (GCC) 4.1.2 (Gentoo 4.1.2)
> 
>     AREA/CLASS/EXAMPLE AFFECTED:
> I've wrote very simple program that demonstrates the problem:
> 
> ################## Simple  example #########################
> 
> #include "ace/Task.h"
> #include <list>
> 
> // Active object.
> class Job : public ACE_Task_Base
> {
>   public:
>     Job()
>       {
>         // Do nothing
>       }
> 
>     virtual ~Job()
>       {
>         // Do nothing
>       }
> 
>     virtual int svc(void)
>       {
>         // Do nothing
>       }
> };
> 
> 
> int main()
> {
>   std::list<Job*> jobs;
> 
>   const int threads_number = 10000;
> 
>   for(int k=0; k<threads_number; ++k)
>     {
>       // Deleting all jobs that have already finished.
>       typedef std::list<Job*>::iterator IT;
>       for(IT i=jobs.begin(); i!=jobs.end(); /* NOP */)
>         {
>           // This condition isn't the same that active
>           // object has become passive ...
>           if( (*i)->thr_count() == 0 )
>             {
>               delete *i;       // and hence BOOM !!!
>               jobs.erase(i++);
>             }
>           else ++i;
>         }
> 
>       // Creating new job.
>       Job* job = new Job;
>       jobs.push_back(job);
> 
>       // Activating job (note: detached mode).
>       assert(job->activate(THR_NEW_LWP |
>                            THR_DETACHED |
>                            THR_INHERIT_SCHED) != -1);
>     }
>   return 0;
> }
> 
> ####################### Makefile ###########################
> BINARY=trouble
> 
> all:
>         g++ -g  main.cpp -lACE -pthread -o $(BINARY)
> clean:
>         rm -f $(BINARY)
> ############################################################
> 
> 
>     DOES THE PROBLEM AFFECT:
>         Execution only.
> 
>     SYNOPSIS:
> Sometimes ACE_Task_Base::thr_count() returns 0 even if the
> object is still active!
> 
>     DESCRIPTION:
> Documentation says about ACE_Task_Base::thr_count():
> Returns the number of threads currently running within a task.
> If we're a passive object this value is 0, else it's greater than 0.
> 
> The problem lies in that sometimes ACE_Task_Base::thr_count()
> returns 0 even if the object is still active!
> 
> Look at the code of ACE_Task_Base::cleanup (with my comments):
> 
> 00227 {
> 00228   ACE_Task_Base *t = (ACE_Task_Base *) object;
> 00229
> 00230   // The thread count must be decremented first in case the
> <close>
> 00231   // hook does something crazy like "delete this".
> 00232   {
> 00233     ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, t->lock_));
> Threads counter is decremented here!
> 00234     t->thr_count_--;
> 00235     if (0 == t->thr_count_)
> 00236       t->last_thread_id_ = ACE_Thread::self ();
> After this line the lock will be released.
> 00237   }
> Suppose that another thread (for example main thread in my program)
> is checking object's state (active or passive) right now.
> It calls thr_count() that returns 0, since we have just decremented
> the value of thr_count_.
> So, if the object is in passive mode it's safe to delete them.
> Am I right?
> And another thread deletes active object using delete operator.
> 00238
> 00239   // @@ Is it possible to pass in the exit status somehow?
> However this object is still active.
> The problem is that it has been already destroyed by another thread!!!
> What happens at this line?
> 00240   t->close ();
> Segmentation fault in my case!!!
> 00241   // t is undefined here. close() could have deleted it.
> 00242 }
> 
>     REPEAT BY:
> I run my test program several times as follows:
> for ((i=1;i<100;i++)) do echo $i ; ./trouble ; done
> 1
> 2
> 3
> ...
> ...
> ...
> 91
> 92
> 93
> Segmentation fault (core dumped)
> 94
> 95
> 96
> 97
> 98
> 99
> 
> 
> What you think about this problem?
> Is it a bug of ACE_Task_Base class?
> 



More information about the Ace-users mailing list