mirror of
https://github.com/cculianu/Fulcrum.git
synced 2026-08-13 12:33:27 +02:00
API nit: Use Util::AsyncOnObject everywhere instead of QTimer::singleShot
This is just to make the API easier to follow. Also cleaned up AsyncOnObject to not default to caarse timer unless the interval is >2000 msec. Also we use QMetaObject::invokeMethod() directly by default if the AsyncOnObjectCall() has when_ms <= 0 (default). This should have no real observable change on app behavior other than being a code cleanup & nit.
This commit is contained in:
parent
92fd99fee8
commit
eba8431a0b
9 changed files with 27 additions and 19 deletions
|
|
@ -100,7 +100,7 @@ App::App(int argc, char *argv[])
|
|||
Log() << "Shutdown requested" << (signalled ? " via signal" : "");
|
||||
this->quit();
|
||||
}, Qt::QueuedConnection);
|
||||
QTimer::singleShot(0, this, &App::startup); // register to run after app event loop start
|
||||
Util::AsyncOnObject(this, [this]{App::startup();}); // register to run after app event loop start
|
||||
}
|
||||
|
||||
App::~App()
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ protected slots:
|
|||
private:
|
||||
friend class CtlTask;
|
||||
/// \brief newTask - Create a specific task using this template factory function. The task will be auto-started the
|
||||
/// next time this thread enters the event loop, via a QTimer::singleShot(0,...).
|
||||
/// next time this thread enters the event loop, via a Util::AsyncOnObject() call
|
||||
///
|
||||
/// \param connectErroredSignal If true, auto-connect signal CtlTask::errored() to this->genericTaskErrored()
|
||||
/// \param args The rest of the args get passed to the c'tor of the concrete class specified (in the template arg).
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
//
|
||||
#include "Common.h"
|
||||
#include "Logger.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
|
|
@ -41,7 +42,7 @@ namespace {
|
|||
{
|
||||
if (level == Logger::Fatal) {
|
||||
if (qApp && !QCoreApplication::startingUp())
|
||||
QTimer::singleShot(0, qApp, []{qApp->exit(1);});
|
||||
Util::AsyncOnObject(qApp, []{qApp->exit(1);});
|
||||
else
|
||||
std::exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ public:
|
|||
virtual ~ProcessAgainMixin() override;
|
||||
protected:
|
||||
virtual void process() = 0;
|
||||
void AGAIN(int when_ms=0) { QTimer::singleShot(qMax(0, when_ms), qobj(), [this]{process();}); }
|
||||
void AGAIN(int when_ms=0) { Util::AsyncOnObject(qobj(), [this]{ process(); }, when_ms); }
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(IdMixin::Id);
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ namespace RPC {
|
|||
readPaused = b;
|
||||
if (!readPaused && hadSkips)
|
||||
// we had some skipped on_readyReads() -- resume
|
||||
QTimer::singleShot(0, this, [this]{on_readyRead();} );
|
||||
Util::AsyncOnObject(this, [this]{on_readyRead();} );
|
||||
emit readPausedStateChanged(readPaused);
|
||||
}
|
||||
|
||||
|
|
@ -1034,7 +1034,7 @@ namespace RPC {
|
|||
if (auto avail = socket->bytesAvailable(); avail > 0 && (MAX_BUFFER <= 0 || avail <= MAX_BUFFER)) {
|
||||
// callback is on socket as receiver this way if socket dies and is deleted, callback never happens.
|
||||
// *taps forehead*
|
||||
QTimer::singleShot(0, socket, [this]{on_readyRead();});
|
||||
Util::AsyncOnObject(socket, [this]{on_readyRead();});
|
||||
}
|
||||
}
|
||||
if (MAX_BUFFER > 0 && socket->bytesAvailable() > MAX_BUFFER) [[unlikely]] {
|
||||
|
|
|
|||
|
|
@ -2583,7 +2583,7 @@ void Storage::save(SaveSpec typed_spec)
|
|||
// atomic variable is not 0).
|
||||
if (const auto spec = IntType(typed_spec); ! p->pendingSaves.fetch_or(spec))
|
||||
{
|
||||
QTimer::singleShot(0, this, [this]{save_impl();});
|
||||
Util::AsyncOnObject(this, [this]{save_impl();});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ void SubsMgr::on_started()
|
|||
}, Qt::QueuedConnection);
|
||||
conns += connect(this, &SubsMgr::requestRemoveZombiesSoon, this, [this](int when_ms) {
|
||||
// remove zombies in when_ms, outside normal rate-limiting timer
|
||||
QTimer::singleShot(std::max(when_ms, 0), this, [this]{ removeZombies(true /* forced */); });
|
||||
Util::AsyncOnObject(this, [this]{ removeZombies(true /* forced */); }, when_ms);
|
||||
}, Qt::QueuedConnection);
|
||||
callOnTimerSoon(kRemoveZombiesTimerIntervalMS, kRemoveZombiesTimerName, [this]{ removeZombies(false); return true;}, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -780,7 +780,7 @@ Log::~Log()
|
|||
}
|
||||
// Fatal should signal a quit even here
|
||||
if (level == Logger::Level::Fatal && qApp) {
|
||||
QTimer::singleShot(0, qApp, []{ qApp->quit(); });
|
||||
Util::AsyncOnObject(qApp, []{ qApp->quit(); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
27
src/Util.h
27
src/Util.h
|
|
@ -651,6 +651,21 @@ namespace Util {
|
|||
/// - the string has an even number of characters (or is empty)
|
||||
bool IsValidHex(const QByteArray &maybeHexStr);
|
||||
|
||||
/// Convenience for just setting up a QTimer::singleShot and/or QMetaObject::invokeMethod on an object, calling a
|
||||
/// lambda as the timeout.
|
||||
/// By default if when_ms is <= 0, the object will have the lambda invoked in its thread as soon as it
|
||||
/// returns to the event loop. Always returns immediately.
|
||||
template <std::invocable VoidFuncT>
|
||||
void AsyncOnObject(const QObject *obj_, const VoidFuncT & lambda, int when_ms=0, std::optional<Qt::TimerType> ttype = std::nullopt) {
|
||||
QObject * const obj = const_cast<QObject *>(obj_); // hacky but it is what it is
|
||||
if (when_ms <= 0) // special case for when_ms is <=0, use invoke instead (avoids allocating a timer)
|
||||
QMetaObject::invokeMethod(obj, lambda, Qt::ConnectionType::QueuedConnection);
|
||||
else {
|
||||
if (!ttype) ttype = when_ms <= 2000 ? Qt::TimerType::PreciseTimer : Qt::TimerType::CoarseTimer;
|
||||
QTimer::singleShot(when_ms, *ttype, obj, lambda);
|
||||
}
|
||||
}
|
||||
|
||||
/// Call lambda() in the thread context of obj's thread. Will block until completed.
|
||||
/// If timeout_ms is not specified or negative, will block forever until lambda returns,
|
||||
/// otherwise will block for timeout_ms ms. Will throw TimeoutException if the timeout
|
||||
|
|
@ -668,7 +683,7 @@ namespace Util {
|
|||
} else {
|
||||
auto taskp = std::make_shared< std::packaged_task<RET()> >(lambda);
|
||||
auto future = taskp->get_future();
|
||||
QTimer::singleShot(0, const_cast<QObject *>(obj), [taskp] { (*taskp)(); });
|
||||
Util::AsyncOnObject(obj, [taskp] { (*taskp)(); });
|
||||
if (timeout_ms >= 0) {
|
||||
if (auto status = future.wait_for(std::chrono::milliseconds(timeout_ms));
|
||||
status != std::future_status::ready) {
|
||||
|
|
@ -698,14 +713,6 @@ namespace Util {
|
|||
/// false otherwise. (Note lambda may still run later asynchronously).
|
||||
bool VoidFuncOnObjectNoThrow(const QObject *obj, const VoidFunc & lambda, int timeout_ms=-1);
|
||||
|
||||
/// Convenience for just setting up a QTimer::singleShot on an object, calling a lambda as the timeout.
|
||||
/// By default if when_ms is 0, the object will have the lambda invoked in its thread as soon as it
|
||||
/// returns to the event loop. Always returns immediately.
|
||||
template <std::invocable VoidFuncT>
|
||||
void AsyncOnObject(const QObject *obj, const VoidFuncT & lambda, unsigned when_ms=0, Qt::TimerType ttype = Qt::TimerType::CoarseTimer) {
|
||||
QTimer::singleShot(int(when_ms), ttype, const_cast<QObject *>(obj), lambda);
|
||||
}
|
||||
|
||||
/// This is an alternative to creating signal/slot pairs for calling a method on an object that runs in another
|
||||
/// thread.
|
||||
///
|
||||
|
|
@ -713,7 +720,7 @@ namespace Util {
|
|||
/// a private slot _myMethod()).
|
||||
///
|
||||
/// To save typing, this template can just allow you to directly call a method on an object in its thread (uses
|
||||
/// QTimer::singleShot).
|
||||
/// QTimer::singleShot and/or QMetaObjecT::invokeMethod).
|
||||
///
|
||||
/// Arguments are capture-copied.
|
||||
///
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue