minor threading fixes

This commit is contained in:
David Rose 2007-11-27 01:18:35 +00:00
parent 0c2b6e3164
commit 4c2659988f
18 changed files with 133 additions and 56 deletions

View File

@ -26,7 +26,6 @@
INLINE AudioLoadRequest:: INLINE AudioLoadRequest::
AudioLoadRequest(AudioManager *audio_manager, const string &filename, AudioLoadRequest(AudioManager *audio_manager, const string &filename,
bool positional) : bool positional) :
AsyncTask(filename),
_audio_manager(audio_manager), _audio_manager(audio_manager),
_filename(filename), _filename(filename),
_positional(positional), _positional(positional),

View File

@ -36,6 +36,9 @@
// an asynchronous load. // an asynchronous load.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_AUDIO AudioLoadRequest : public AsyncTask { class EXPCL_PANDA_AUDIO AudioLoadRequest : public AsyncTask {
public:
ALLOC_DELETED_CHAIN(AudioLoadRequest);
PUBLISHED: PUBLISHED:
INLINE AudioLoadRequest(AudioManager *audio_manager, const string &filename, INLINE AudioLoadRequest(AudioManager *audio_manager, const string &filename,
bool positional); bool positional);

View File

@ -23,8 +23,7 @@
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE AsyncTask:: INLINE AsyncTask::
AsyncTask(const string &name) : AsyncTask() :
Namable(name),
_state(S_inactive), _state(S_inactive),
_manager(NULL) _manager(NULL)
{ {

View File

@ -37,5 +37,5 @@ AsyncTask::
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void AsyncTask:: void AsyncTask::
output(ostream &out) const { output(ostream &out) const {
out << get_type() << " " << get_name(); out << get_type();
} }

View File

@ -43,10 +43,11 @@ class AsyncTaskManager;
// class, and override do_task(), to define the // class, and override do_task(), to define the
// functionality you wish to have the task perform. // functionality you wish to have the task perform.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_EVENT AsyncTask : public TypedReferenceCount, public Namable { class EXPCL_PANDA_EVENT AsyncTask : public TypedReferenceCount {
public: public:
INLINE AsyncTask(const string &name); INLINE AsyncTask();
virtual ~AsyncTask(); virtual ~AsyncTask();
ALLOC_DELETED_CHAIN(AsyncTask);
PUBLISHED: PUBLISHED:
enum State { enum State {

View File

@ -194,6 +194,7 @@ remove(AsyncTask *task) {
// serviced. Wait for it to finish. // serviced. Wait for it to finish.
while (task->_manager == this && while (task->_manager == this &&
task->_state == AsyncTask::S_servicing) { task->_state == AsyncTask::S_servicing) {
PStatTimer timer(_wait_pcollector);
_cvar.wait(); _cvar.wait();
} }
@ -235,6 +236,37 @@ has_task(AsyncTask *task) const {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: AsyncTaskManager::wait_for_tasks
// Access: Published
// Description: Blocks until the task list is empty.
////////////////////////////////////////////////////////////////////
void AsyncTaskManager::
wait_for_tasks() {
MutexHolder holder(_lock);
if (_threads.empty()) {
// Non-threaded case.
while (!_active.empty()) {
if (_state == AsyncTaskManager::S_shutdown) {
return;
}
do_poll();
}
} else {
// Threaded case.
while (_num_tasks > 0) {
if (_state == AsyncTaskManager::S_shutdown) {
return;
}
PStatTimer timer(_wait_pcollector);
_cvar.wait();
}
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: AsyncTaskManager::poll // Function: AsyncTaskManager::poll
// Access: Published // Access: Published
@ -250,32 +282,8 @@ poll() {
if (!_threads.empty()) { if (!_threads.empty()) {
return; return;
} }
Tasks new_active; do_poll();
int new_num_tasks = 0;
Tasks::iterator ti;
for (ti = _active.begin(); ti != _active.end(); ++ti) {
AsyncTask *task = (*ti);
nassertv(task->_state == AsyncTask::S_active);
task->_state = AsyncTask::S_servicing;
// Here we keep the manager lock held while we are servicing each
// task. This is the single-threaded implementation, after all,
// so what difference should it make?
if (task->do_task()) {
new_active.push_back(task);
++new_num_tasks;
task->_state = AsyncTask::S_active;
} else {
// The task has finished.
task_done(task);
}
}
_active.swap(new_active);
_num_tasks = new_num_tasks;
_cvar.signal_all();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -417,7 +425,9 @@ do_start_threads() {
if (Thread::is_threading_supported()) { if (Thread::is_threading_supported()) {
_threads.reserve(_num_threads); _threads.reserve(_num_threads);
for (int i = 0; i < _num_threads; ++i) { for (int i = 0; i < _num_threads; ++i) {
PT(AsyncTaskManagerThread) thread = new AsyncTaskManagerThread(this); ostringstream strm;
strm << get_name() << "_" << i;
PT(AsyncTaskManagerThread) thread = new AsyncTaskManagerThread(strm.str(), this);
if (thread->start(TP_low, true)) { if (thread->start(TP_low, true)) {
_threads.push_back(thread); _threads.push_back(thread);
} }
@ -426,14 +436,49 @@ do_start_threads() {
} }
} }
////////////////////////////////////////////////////////////////////
// Function: AsyncTaskManager::do_poll
// Access: Protected
// Description: The private implementation of poll(), this assumes
// the lock is already held.
////////////////////////////////////////////////////////////////////
void AsyncTaskManager::
do_poll() {
Tasks new_active;
int new_num_tasks = 0;
Tasks::iterator ti;
for (ti = _active.begin(); ti != _active.end(); ++ti) {
AsyncTask *task = (*ti);
nassertv(task->_state == AsyncTask::S_active);
task->_state = AsyncTask::S_servicing;
// Here we keep the manager lock held while we are servicing each
// task. This is the single-threaded implementation, after all,
// so what difference should it make?
if (task->do_task()) {
new_active.push_back(task);
++new_num_tasks;
task->_state = AsyncTask::S_active;
} else {
// The task has finished.
task_done(task);
}
}
_active.swap(new_active);
_num_tasks = new_num_tasks;
_cvar.signal_all();
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: AsyncTaskManager::AsyncTaskManagerThread::Constructor // Function: AsyncTaskManager::AsyncTaskManagerThread::Constructor
// Access: Public // Access: Public
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
AsyncTaskManager::AsyncTaskManagerThread:: AsyncTaskManager::AsyncTaskManagerThread::
AsyncTaskManagerThread(AsyncTaskManager *manager) : AsyncTaskManagerThread(const string &name, AsyncTaskManager *manager) :
Thread(manager->get_name(), manager->get_name()), Thread(name, manager->get_name()),
_manager(manager), _manager(manager),
_servicing(NULL) _servicing(NULL)
{ {

View File

@ -50,7 +50,7 @@
class EXPCL_PANDA_EVENT AsyncTaskManager : public TypedReferenceCount, public Namable { class EXPCL_PANDA_EVENT AsyncTaskManager : public TypedReferenceCount, public Namable {
PUBLISHED: PUBLISHED:
AsyncTaskManager(const string &name, int num_threads); AsyncTaskManager(const string &name, int num_threads);
virtual ~AsyncTaskManager(); BLOCKING virtual ~AsyncTaskManager();
INLINE int get_num_threads() const; INLINE int get_num_threads() const;
BLOCKING void stop_threads(); BLOCKING void stop_threads();
@ -62,6 +62,8 @@ PUBLISHED:
bool remove(AsyncTask *task); bool remove(AsyncTask *task);
bool has_task(AsyncTask *task) const; bool has_task(AsyncTask *task) const;
BLOCKING void wait_for_tasks();
INLINE int get_num_tasks() const; INLINE int get_num_tasks() const;
void poll(); void poll();
@ -76,11 +78,12 @@ protected:
void service_one_task(AsyncTaskManagerThread *thread); void service_one_task(AsyncTaskManagerThread *thread);
void task_done(AsyncTask *task); void task_done(AsyncTask *task);
void do_start_threads(); void do_start_threads();
void do_poll();
protected: protected:
class AsyncTaskManagerThread : public Thread { class AsyncTaskManagerThread : public Thread {
public: public:
AsyncTaskManagerThread(AsyncTaskManager *manager); AsyncTaskManagerThread(const string &name, AsyncTaskManager *manager);
virtual void thread_main(); virtual void thread_main();
AsyncTaskManager *_manager; AsyncTaskManager *_manager;

View File

@ -251,6 +251,7 @@ end_traverse() {
#endif // NDEBUG #endif // NDEBUG
} }
_pending_objects.clear(); _pending_objects.clear();
CullTraverser::end_traverse();
gsg->end_scene(); gsg->end_scene();
_buffer->end_frame(GraphicsOutput::FM_render, current_thread); _buffer->end_frame(GraphicsOutput::FM_render, current_thread);

View File

@ -23,6 +23,15 @@
#include "renderState.h" #include "renderState.h"
#include "pnotify.h" #include "pnotify.h"
////////////////////////////////////////////////////////////////////
// Function: CullHandler::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CullHandler::
CullHandler() {
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CullHandler::Destructor // Function: CullHandler::Destructor
// Access: Public, Virtual // Access: Public, Virtual
@ -50,6 +59,17 @@ record_object(CullableObject *object, const CullTraverser *traverser) {
delete object; delete object;
} }
////////////////////////////////////////////////////////////////////
// Function: CullHandler::end_traverse
// Access: Public, Virtual
// Description: This callback function is intended to be overridden
// by a derived class. This is called at the end of the
// traversal.
////////////////////////////////////////////////////////////////////
void CullHandler::
end_traverse() {
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CullHandler::draw_with_decals // Function: CullHandler::draw_with_decals
// Access: Public, Static // Access: Public, Static

View File

@ -34,10 +34,12 @@ class CullTraverser;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH CullHandler { class EXPCL_PANDA_PGRAPH CullHandler {
public: public:
CullHandler();
virtual ~CullHandler(); virtual ~CullHandler();
virtual void record_object(CullableObject *object, virtual void record_object(CullableObject *object,
const CullTraverser *traverser); const CullTraverser *traverser);
virtual void end_traverse();
INLINE static void draw(CullableObject *object, INLINE static void draw(CullableObject *object,
GraphicsStateGuardianBase *gsg, GraphicsStateGuardianBase *gsg,

View File

@ -17,19 +17,6 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CullResult::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE CullResult::
CullResult(GraphicsStateGuardianBase *gsg,
const PStatCollector &draw_region_pcollector) :
_gsg(gsg),
_draw_region_pcollector(draw_region_pcollector)
{
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CullResult::Destructor // Function: CullResult::Destructor
// Access: Public // Access: Public

View File

@ -56,6 +56,19 @@
static const float dual_opaque_level = 252.0f / 256.0f; static const float dual_opaque_level = 252.0f / 256.0f;
static const double bin_color_flash_rate = 1.0; // 1 state change per second static const double bin_color_flash_rate = 1.0; // 1 state change per second
////////////////////////////////////////////////////////////////////
// Function: CullResult::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CullResult::
CullResult(GraphicsStateGuardianBase *gsg,
const PStatCollector &draw_region_pcollector) :
_gsg(gsg),
_draw_region_pcollector(draw_region_pcollector)
{
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CullResult::make_next // Function: CullResult::make_next
// Access: Public // Access: Public

View File

@ -24,7 +24,6 @@
#include "renderState.h" #include "renderState.h"
#include "cullableObject.h" #include "cullableObject.h"
#include "geomMunger.h" #include "geomMunger.h"
#include "referenceCount.h" #include "referenceCount.h"
#include "pointerTo.h" #include "pointerTo.h"
#include "pvector.h" #include "pvector.h"
@ -51,8 +50,8 @@ class SceneSetup;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount { class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount {
public: public:
INLINE CullResult(GraphicsStateGuardianBase *gsg, CullResult(GraphicsStateGuardianBase *gsg,
const PStatCollector &draw_region_pcollector); const PStatCollector &draw_region_pcollector);
INLINE ~CullResult(); INLINE ~CullResult();
PT(CullResult) make_next() const; PT(CullResult) make_next() const;
@ -81,7 +80,7 @@ private:
GraphicsStateGuardianBase *_gsg; GraphicsStateGuardianBase *_gsg;
PStatCollector _draw_region_pcollector; PStatCollector _draw_region_pcollector;
typedef pvector< PT(CullBin) > Bins; typedef pvector< PT(CullBin) > Bins;
Bins _bins; Bins _bins;
}; };

View File

@ -359,6 +359,7 @@ traverse_below(CullTraverserData &data) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CullTraverser:: void CullTraverser::
end_traverse() { end_traverse() {
_cull_handler->end_traverse();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -25,7 +25,6 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE ModelFlattenRequest:: INLINE ModelFlattenRequest::
ModelFlattenRequest(PandaNode *orig) : ModelFlattenRequest(PandaNode *orig) :
AsyncTask(orig->get_name()),
_orig(orig), _orig(orig),
_is_ready(false) _is_ready(false)
{ {

View File

@ -35,6 +35,9 @@
// retrieved from this object. // retrieved from this object.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH ModelFlattenRequest : public AsyncTask { class EXPCL_PANDA_PGRAPH ModelFlattenRequest : public AsyncTask {
public:
ALLOC_DELETED_CHAIN(ModelFlattenRequest);
PUBLISHED: PUBLISHED:
INLINE ModelFlattenRequest(PandaNode *orig); INLINE ModelFlattenRequest(PandaNode *orig);

View File

@ -25,7 +25,6 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE ModelLoadRequest:: INLINE ModelLoadRequest::
ModelLoadRequest(const Filename &filename, const LoaderOptions &options) : ModelLoadRequest(const Filename &filename, const LoaderOptions &options) :
AsyncTask(filename),
_filename(filename), _filename(filename),
_options(options), _options(options),
_is_ready(false) _is_ready(false)

View File

@ -35,6 +35,9 @@
// an asynchronous load. // an asynchronous load.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH ModelLoadRequest : public AsyncTask { class EXPCL_PANDA_PGRAPH ModelLoadRequest : public AsyncTask {
public:
ALLOC_DELETED_CHAIN(ModelLoadRequest);
PUBLISHED: PUBLISHED:
INLINE ModelLoadRequest(const Filename &filename, INLINE ModelLoadRequest(const Filename &filename,
const LoaderOptions &options); const LoaderOptions &options);