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

Douglas C. Schmidt schmidt at dre.vanderbilt.edu
Wed Jul 11 15:38:07 CDT 2007


Hi Folks,

   This seems like it's becoming a FAQ ;-)  Dmitry, please take a look at
chapter 9 of C++NPv1 <www.cs.wustl.edu/~schmidt/ACE/book1> and chapter 6
of C++NPv2 <www.cs.wustl.edu/~schmidt/ACE/book2> for information on
how/why to wait for threads before exiting main().

      Thanks,
      
      Doug

> 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?
> > 
> 
> _______________________________________________
> ace-users mailing list
> ace-users at mail.cse.wustl.edu
> http://mail.cse.wustl.edu/mailman/listinfo/ace-users



More information about the Ace-users mailing list