You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Seiji Sam Lee <se...@gmail.com> on 2010/03/25 14:29:40 UTC

Problems with apr_thread_join (again) on Windows

Yes, I have a problem with apr_thread_join in Windows which was resolved in
previous versions. 

Simply when the thread isn't detached this function wait forever .

 

I had tested all possible causes. Are there any with the same problem?

 

COPY/PASTE my code for check:

 

////////////////////// THREAD.H
///////////////////////////////////////////////////////////////////

 

class Thread

 {

  public:

    enum ThreadState { EMPTY=0, PAUSED=1, RUNNING=2, STOPPED=3 };

    

  private:

    apr_thread_t*        _thread;

    apr_thread_mutex_t*  _mutex;

    apr_thread_cond_t*   _condition;

    volatile bool        _finalize;

    volatile ThreadState _status;

    volatile uint32_t    _interval;

    volatile uint32_t    _counter;

    

    friend void*APR_THREAD_FUNC _thread_stub(apr_thread_t*,void*);

    

  protected:

    virtual bool _execute()=0;

    void         _wait(uint32_t time=0);

    

  public:

    Thread(uint32_t _int=0,uint32_t _cnt=0);

   ~Thread();

   

    bool         run(apr_pool_t*,bool start);

    void         resume();

    void         pause();

    apr_status_t join();

    ThreadState  state() { return _status; }

    void         signal();

    uint32_t     interval() { return _interval; }

    void         interval(uint32_t n) { _interval=n;signal(); }

    uint32_t     counter() { return _counter; }

    void         counter(uint32_t n) { _counter=n;signal(); }

 };

 

////////////////////// THREAD.CPP
/////////////////////////////////////////////////////////////////

 

 #define SET(var,val) apr_atomic_set32((volatile
apr_uint32_t*)&(var),(apr_uint32_t)(val))

 #define GET(var)     apr_atomic_read32((volatile apr_uint32_t*)&(var))

 

 static void* APR_THREAD_FUNC _thread_stub(apr_thread_t*thread,void*data)

 {

  CHECK(data!=NULL);

  Thread*self=(Thread*)data;

  apr_status_t retval=APR_SUCCESS;

  uint32_t times=0;

  while(!GET(self->_finalize) && (GET(self->_counter)==0 ||
GET(self->_counter)>times))

       {

        if(GET(self->_status)==Thread::PAUSED)

          {

           self->_wait();

          }

        else

        if(GET(self->_status)==Thread::RUNNING)

          {  

           try 

             { 

              if(GET(self->_interval)>0) self->_wait(GET(self->_interval));

              if(!GET(self->_finalize) && (GET(self->_counter)==0 ||
GET(self->_counter)>times))

                {

                 SET(self->_finalize,self->_execute()); 

                 times+=1;

                }

             } 

           catch(...) 

             { 

              retval=APR_INCOMPLETE;

              SET(self->_finalize,true); 

             }

          }

        else

          {

           apr_thread_yield();

          }

       }

  do { apr_thread_yield(); } while(GET(self->_status)!=Thread::STOPPED);

  apr_thread_exit(thread,retval);

  return NULL;

 }

 

 Thread::Thread(uint32_t _int,uint32_t _cnt)

 {

  _thread=NULL;

  _mutex=NULL;

  _condition=NULL;

  SET(_status,Thread::EMPTY);

  SET(_finalize,0);

  SET(_interval,_int);

  SET(_counter,_cnt);

 }

 

 Thread::~Thread()

 {

  join();

 }

 

 void Thread::_wait(uint32_t time)

 {

  if(GET(_status)!=Thread::EMPTY && GET(_status)!=Thread::STOPPED)

    {

     apr_thread_mutex_lock(_mutex);

     if(time==0) apr_thread_cond_wait(_condition,_mutex);

     else        apr_thread_cond_timedwait(_condition,_mutex,time);

     apr_thread_mutex_unlock(_mutex);

    }

 }

 

 bool Thread::run(apr_pool_t*_pool,bool start)

 {

  if(GET(_status)==Thread::EMPTY)

    {

 
if(apr_thread_create(&_thread,NULL,_thread_stub,this,_pool)==APR_SUCCESS)

       {

        apr_thread_cond_create(&_condition,_pool);

        apr_thread_mutex_create(&_mutex,APR_THREAD_MUTEX_NESTED,_pool);

        SET(_status,( !start ? Thread::PAUSED : Thread::RUNNING ));

       }

    }

  return (GET(_status)==Thread::RUNNING);

 }

 

 void Thread::resume()

 {

  if(GET(_status)==Thread::PAUSED)

    {

     SET(_status,Thread::RUNNING);

     signal();

    }

 }

 

 void Thread::pause()

 {

  if(GET(_status)==Thread::RUNNING)

    {

     SET(_status,Thread::PAUSED);

     signal();

    }

 }

 

 apr_status_t Thread::join()

 {

  apr_status_t ret=APR_SUCCESS;

  if(GET(_status)==Thread::PAUSED || GET(_status)==Thread::RUNNING)

    {

     SET(_finalize,true);

     signal();

     SET(_status,Thread::STOPPED);

     apr_thread_join(&ret,_thread);

     //NEVER REACH THIS POINT

     apr_thread_cond_destroy(_condition);

     apr_thread_mutex_destroy(_mutex);

     _thread=NULL;

     _mutex=NULL;

     _condition=NULL;

     SET(_finalize,0);

     SET(_status,Thread::EMPTY);

    }

  return ret;

 }

 

 void Thread::signal()

 {

  if(GET(_status)!=Thread::EMPTY && GET(_status)!=Thread::STOPPED)

    {

     apr_thread_mutex_lock(_mutex);

     apr_thread_cond_signal(_condition);

     apr_thread_mutex_unlock(_mutex);

    }

 }