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);
}
}