Use GenericThread, and use usleep instead of QTimer (which is incompatible with GenericThread).

This commit is contained in:
Howard Stearns 2015-08-26 11:59:12 -07:00
parent b0734a06f3
commit 54877cdd47
2 changed files with 29 additions and 94 deletions

View file

@ -24,50 +24,22 @@
// As it turns out, all the other subclasses of GenericThread (at this time) do not init
// GenericThread(parent), so things work as expected. Here we explicitly init GenericThread(nullptr)
// so that there is no confusion and no chance for a hillarious thread debugging session.
AvatarUpdate::AvatarUpdate() : QObject(nullptr), _lastAvatarUpdate(0), _timer(nullptr), _thread(nullptr)/*FIXME remove*/ {
AvatarUpdate::AvatarUpdate() : GenericThread(nullptr), _lastAvatarUpdate(0)/*, _timer(nullptr), _thread(nullptr)FIXME remove*/ {
setObjectName("Avatar Update"); // GenericThread::initialize uses this to set the thread name.
Settings settings;
const int DEFAULT_TARGET_AVATAR_SIMRATE = 60;
_targetInterval = USECS_PER_SECOND / settings.value("AvatarUpdateTargetSimrate", DEFAULT_TARGET_AVATAR_SIMRATE).toInt();
_type = settings.value("AvatarUpdateType", UpdateType::Synchronous).toInt();
qCDebug(interfaceapp) << "AvatarUpdate using" << _type << "at" << _targetInterval << "microseconds";
_isToBeThreaded = settings.value("AvatarUpdateIsThreaded", true).toBool();
if (_isToBeThreaded) {
qCDebug(interfaceapp) << "AvatarUpdate threaded at" << _targetInterval << "microsecond interval.";
} else {
qCDebug(interfaceapp) << "AvatarUpdate unthreaded.";
}
}
// We could have the constructor call initialize(), but GenericThread::initialize can take parameters.
// Keeping it separately called by the client allows that client to pass those without our
// constructor needing to know about them.
// GenericThread::terimate() calls terminating() only when _isThreaded, so it's not good enough
// to just override terminating(). Instead, we extend terminate();
void AvatarUpdate::terminate() {
if (_timer) {
_timer->stop();
}
// FIXME: GenericThread::terminate();
if (_thread) {
_thread->quit();
}
}
// QTimer runs in the thread that starts it.
// threadRoutine() is called once within the separate thread (if any),
// or on each main loop update via synchronousProcess();
void AvatarUpdate::threadRoutine() {
if (!_timer && (_type != UpdateType::Synchronous)) {
initTimer();
}
if (!_timer) {
process();
}
}
void AvatarUpdate::initTimer() {
_timer = new QTimer(this);
/*FIXME connect(_timer, &QTimer::timeout, this, &AvatarUpdate::process);
_timer->start(_targetInterval / USECS_PER_MSEC);*/
while (true) {
process();
}
}
void AvatarUpdate::synchronousProcess() {
// Keep our own updated value, so that our asynchronous code can consult it.
@ -78,14 +50,17 @@ void AvatarUpdate::synchronousProcess() {
Application::getInstance()->getMyAvatar()->doUpdateBillboard();
}
//threadRoutine();
//process(); //fixme
if (isThreaded()) {
return;
}
process();
}
bool AvatarUpdate::process() {
PerformanceTimer perfTimer("AvatarUpdate");
quint64 start = usecTimestampNow();
quint64 deltaMicroseconds = start - _lastAvatarUpdate;
_lastAvatarUpdate = start;
float deltaSeconds = deltaMicroseconds / (float) USECS_PER_SECOND;
Application::getInstance()->setAvatarSimrateSample(1.0f / deltaSeconds);
@ -96,29 +71,15 @@ bool AvatarUpdate::process() {
Application::getInstance()->updateMyAvatarLookAtPosition();
// Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
DependencyManager::get<AvatarManager>()->updateMyAvatar(deltaSeconds);
if (isToBeThreaded()) {
int elapsed = (usecTimestampNow() - start);
int usecToSleep = _targetInterval - elapsed;
if (usecToSleep < 0) {
usecToSleep = 1; // always yield
}
usleep(usecToSleep);
}
_lastAvatarUpdate = start;
if (!isThreaded()) {
return true;
}
int elapsed = (usecTimestampNow() - start);
int usecToSleep = _targetInterval - elapsed;
if (usecToSleep < 0) {
usecToSleep = 1; // always yield
}
usleep(usecToSleep);
return true;
}
// To be removed with GenericThread
void AvatarUpdate::initialize(bool isThreaded) { //fixme remove
if (isThreaded) {
initThread();
}
}
void AvatarUpdate::initThread() {
_thread = new QThread();
_thread->setObjectName(objectName());
this->moveToThread(_thread);
connect(_thread, &QThread::started, this, &AvatarUpdate::threadRoutine);
_thread->start();
}

View file

@ -15,50 +15,24 @@
#include <QtCore/QObject>
#include <QTimer>
// There are a couple of ways we could do this.
// Right now, the goals are:
// 1. allow development to switch between UpdateType
// e.g.: see uses of UpdateType.
// 2. minimize changes everwhere, particularly outside of Avatars.
// e.g.: we could make Application::isHMDMode() thread safe, but for now we just made AvatarUpdate::isHMDMode() thread safe.
// Home for the avatarUpdate operations (e.g., whether on a separate thread, pipelined in various ways, etc.)
// This might get folded into AvatarManager.
class AvatarUpdate : public QObject {
class AvatarUpdate : public GenericThread {
Q_OBJECT
public:
AvatarUpdate();
void synchronousProcess();
void setRequestBillboardUpdate(bool needsUpdate) { _updateBillboard = needsUpdate; }
void terminate(); // Extends GenericThread::terminate to also kill timer.
bool isToBeThreaded() { return _isToBeThreaded; }
private:
virtual bool process(); // No reason for other classes to invoke this.
void initTimer();
quint64 _targetInterval; // microseconds
bool _updateBillboard;
quint64 _lastAvatarUpdate; // microsoeconds
// Goes away when we get rid of the ability to switch back and forth in settings:
enum UpdateType {
Synchronous = 1,
Timer,
Thread
};
int _type;
public:
bool isToBeThreaded() const { return _type == UpdateType::Thread; } // Currently set by constructor from settings.
void threadRoutine();
// Goes away when using GenericThread:
void initialize(bool isThreaded);
private:
QTimer* _timer;
QThread* _thread;
void initThread();
// Goes away if Applicaiton::isHMDMode() and friends are made thread safe:
quint64 _targetInterval; // microseconds
bool _isToBeThreaded;
bool _updateBillboard;
// Goes away if Application::getActiveDisplayPlugin() and friends are made thread safe:
public:
bool isHMDMode() { return _isHMDMode; }
glm::mat4 getHeadPose() { return _headPose; }