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::
AudioLoadRequest(AudioManager *audio_manager, const string &filename,
bool positional) :
AsyncTask(filename),
_audio_manager(audio_manager),
_filename(filename),
_positional(positional),

View File

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

View File

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

View File

@ -37,5 +37,5 @@ AsyncTask::
////////////////////////////////////////////////////////////////////
void AsyncTask::
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
// 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:
INLINE AsyncTask(const string &name);
INLINE AsyncTask();
virtual ~AsyncTask();
ALLOC_DELETED_CHAIN(AsyncTask);
PUBLISHED:
enum State {

View File

@ -194,6 +194,7 @@ remove(AsyncTask *task) {
// serviced. Wait for it to finish.
while (task->_manager == this &&
task->_state == AsyncTask::S_servicing) {
PStatTimer timer(_wait_pcollector);
_cvar.wait();
}
@ -235,6 +236,37 @@ has_task(AsyncTask *task) const {
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
// Access: Published
@ -250,32 +282,8 @@ poll() {
if (!_threads.empty()) {
return;
}
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();
do_poll();
}
////////////////////////////////////////////////////////////////////
@ -417,7 +425,9 @@ do_start_threads() {
if (Thread::is_threading_supported()) {
_threads.reserve(_num_threads);
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)) {
_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
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AsyncTaskManager::AsyncTaskManagerThread::
AsyncTaskManagerThread(AsyncTaskManager *manager) :
Thread(manager->get_name(), manager->get_name()),
AsyncTaskManagerThread(const string &name, AsyncTaskManager *manager) :
Thread(name, manager->get_name()),
_manager(manager),
_servicing(NULL)
{

View File

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

View File

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

View File

@ -23,6 +23,15 @@
#include "renderState.h"
#include "pnotify.h"
////////////////////////////////////////////////////////////////////
// Function: CullHandler::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CullHandler::
CullHandler() {
}
////////////////////////////////////////////////////////////////////
// Function: CullHandler::Destructor
// Access: Public, Virtual
@ -50,6 +59,17 @@ record_object(CullableObject *object, const CullTraverser *traverser) {
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
// Access: Public, Static

View File

@ -34,10 +34,12 @@ class CullTraverser;
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH CullHandler {
public:
CullHandler();
virtual ~CullHandler();
virtual void record_object(CullableObject *object,
const CullTraverser *traverser);
virtual void end_traverse();
INLINE static void draw(CullableObject *object,
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
// Access: Public

View File

@ -56,6 +56,19 @@
static const float dual_opaque_level = 252.0f / 256.0f;
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
// Access: Public

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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