fix some threading issues

This commit is contained in:
David Rose 2008-09-28 17:11:42 +00:00
parent 8bb89607ab
commit a29328046a
8 changed files with 101 additions and 50 deletions

View File

@ -1373,14 +1373,18 @@ thread_main() {
// If we've exceeded our frame budget, sleep until the next
// frame.
while (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget) {
_chain->cleanup_pickup_mode();
_chain->_manager->_frame_cvar.wait();
frame = _chain->_manager->_clock->get_frame_count();
if (_chain->_current_frame != frame) {
_chain->_current_frame = frame;
_chain->_time_in_frame = 0.0;
if (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget) {
while (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget) {
_chain->cleanup_pickup_mode();
_chain->_manager->_frame_cvar.wait();
frame = _chain->_manager->_clock->get_frame_count();
if (_chain->_current_frame != frame) {
_chain->_current_frame = frame;
_chain->_time_in_frame = 0.0;
}
}
// Now that it's the next frame, go back to the top of the loop.
continue;
}
PStatTimer timer(_task_pcollector);

View File

@ -313,6 +313,30 @@ __getattr__(const string &attr_name) const {
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus PythonTask::
do_task() {
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
// Use PyGILState to protect this asynchronous call.
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
#endif
DoneStatus result = do_python_task();
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyGILState_Release(gstate);
#endif
return result;
}
////////////////////////////////////////////////////////////////////
// Function: PythonTask::do_python_task
// Access: Protected
// Description: The Python calls that implement do_task(). This
// function is separate so we can acquire the Python
// interpretor lock while it runs.
////////////////////////////////////////////////////////////////////
AsyncTask::DoneStatus PythonTask::
do_python_task() {
PyObject *result = NULL;
if (_generator == (PyObject *)NULL) {
@ -419,7 +443,18 @@ do_task() {
void PythonTask::
upon_birth() {
AsyncTask::upon_birth();
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
// Use PyGILState to protect this asynchronous call.
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
#endif
call_owner_method("_addTask");
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyGILState_Release(gstate);
#endif
}
////////////////////////////////////////////////////////////////////
@ -442,8 +477,19 @@ upon_birth() {
void PythonTask::
upon_death(bool clean_exit) {
AsyncTask::upon_death(clean_exit);
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
// Use PyGILState to protect this asynchronous call.
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
#endif
call_owner_method("_clearTask");
call_function(_upon_death);
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyGILState_Release(gstate);
#endif
}
////////////////////////////////////////////////////////////////////

View File

@ -49,6 +49,7 @@ PUBLISHED:
protected:
virtual DoneStatus do_task();
DoneStatus do_python_task();
virtual void upon_birth();
virtual void upon_death(bool clean_exit);

View File

@ -38,7 +38,7 @@ wait(double timeout) {
int seconds = (int)floor(timeout);
ts.tv_sec += seconds;
ts.tv_nsec += (timeout - seconds) * 1000000.0;
ts.tv_nsec += (int)((timeout - seconds) * 1000000.0);
int result = pthread_cond_timedwait(&_cvar, &_mutex._lock, &ts);
nassertv(result == 0);

View File

@ -50,12 +50,6 @@ PythonThread(PyObject *function, PyObject *args,
nassert_raise("Invalid args passed to PythonThread constructor");
}
}
#ifndef SIMPLE_THREADS
// Ensure that the Python threading system is initialized and ready
// to go.
PyEval_InitThreads();
#endif
}
////////////////////////////////////////////////////////////////////

View File

@ -13,40 +13,6 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: Thread::Constructor
// Access: Protected
// Description: Creates a new Thread object, but does not
// immediately start executing it. This gives the
// caller a chance to store it in a PT(Thread) object,
// if desired, before the thread gets a chance to
// terminate and destruct itself.
//
// Call start() to begin thread execution.
//
// The name should be unique for each thread (though
// this is not enforced, and not strictly required).
// The sync_name can be shared between multiple
// different threads; threads that run synchronously
// with each other should be given the same sync_name,
// for the benefit of PStats.
////////////////////////////////////////////////////////////////////
INLINE Thread::
Thread(const string &name, const string &sync_name) :
_name(name),
_sync_name(sync_name),
_impl(this)
{
_started = false;
_pstats_index = -1;
_pstats_callback = NULL;
_pipeline_stage = 0;
#ifdef DEBUG_THREADS
_blocked_on_mutex = NULL;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: Thread::Copy Constructor
// Access: Private

View File

@ -21,6 +21,46 @@ Thread *Thread::_main_thread;
Thread *Thread::_external_thread;
TypeHandle Thread::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: Thread::Constructor
// Access: Protected
// Description: Creates a new Thread object, but does not
// immediately start executing it. This gives the
// caller a chance to store it in a PT(Thread) object,
// if desired, before the thread gets a chance to
// terminate and destruct itself.
//
// Call start() to begin thread execution.
//
// The name should be unique for each thread (though
// this is not enforced, and not strictly required).
// The sync_name can be shared between multiple
// different threads; threads that run synchronously
// with each other should be given the same sync_name,
// for the benefit of PStats.
////////////////////////////////////////////////////////////////////
Thread::
Thread(const string &name, const string &sync_name) :
_name(name),
_sync_name(sync_name),
_impl(this)
{
_started = false;
_pstats_index = -1;
_pstats_callback = NULL;
_pipeline_stage = 0;
#ifdef DEBUG_THREADS
_blocked_on_mutex = NULL;
#endif
#if defined(HAVE_PYTHON) && !defined(SIMPLE_THREADS)
// Ensure that the Python threading system is initialized and ready
// to go.
PyEval_InitThreads();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: Thread::Destructor
// Access: Published, Virtual
@ -239,7 +279,7 @@ call_python_func(PyObject *function, PyObject *args) {
}
#else // SIMPLE_THREADS
// With true threading enabled, we're better off using PyGILSTate.
// With true threading enabled, we're better off using PyGILState.
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

View File

@ -46,7 +46,7 @@ class MutexDebug;
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PIPELINE Thread : public TypedReferenceCount {
protected:
INLINE Thread(const string &name, const string &sync_name);
Thread(const string &name, const string &sync_name);
PUBLISHED:
virtual ~Thread();