40617436c6
1f668b6 Expose if CScheduler is being serviced, assert its not in EmptyQueue (Matt Corallo) 3192975 Flush CValidationInterface callbacks prior to destruction (Matt Corallo) 08096bb Support more than one CScheduler thread for serial clients (Matt Corallo) 2fbf2db Add default arg to CScheduler to schedule() a callback now (Matt Corallo) cda1429 Give CMainSignals a reference to the global scheduler (Matt Corallo) 3a19fed Make ValidationInterface signals-type-agnostic (Matt Corallo) ff6a834 Use TestingSetup to DRY qt rpcnestedtests (Matt Corallo) Tree-SHA512: fab91e34e30b080ed4d0a6d8c1214910e383c45440676e37be61d0bde6ae98d61e8903d22b846e95ba4e73a6ce788798350266feba246d8a2ab357e8523e4ac5
114 lines
3.8 KiB
C++
114 lines
3.8 KiB
C++
// Copyright (c) 2015 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef BITCOIN_SCHEDULER_H
|
|
#define BITCOIN_SCHEDULER_H
|
|
|
|
//
|
|
// NOTE:
|
|
// boost::thread / boost::chrono should be ported to std::thread / std::chrono
|
|
// when we support C++11.
|
|
//
|
|
#include <boost/chrono/chrono.hpp>
|
|
#include <boost/thread.hpp>
|
|
#include <map>
|
|
|
|
#include "sync.h"
|
|
|
|
//
|
|
// Simple class for background tasks that should be run
|
|
// periodically or once "after a while"
|
|
//
|
|
// Usage:
|
|
//
|
|
// CScheduler* s = new CScheduler();
|
|
// s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { }
|
|
// s->scheduleFromNow(std::bind(Class::func, this, argument), 3);
|
|
// boost::thread* t = new boost::thread(boost::bind(CScheduler::serviceQueue, s));
|
|
//
|
|
// ... then at program shutdown, clean up the thread running serviceQueue:
|
|
// t->interrupt();
|
|
// t->join();
|
|
// delete t;
|
|
// delete s; // Must be done after thread is interrupted/joined.
|
|
//
|
|
|
|
class CScheduler
|
|
{
|
|
public:
|
|
CScheduler();
|
|
~CScheduler();
|
|
|
|
typedef std::function<void(void)> Function;
|
|
|
|
// Call func at/after time t
|
|
void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now());
|
|
|
|
// Convenience method: call f once deltaSeconds from now
|
|
void scheduleFromNow(Function f, int64_t deltaMilliSeconds);
|
|
|
|
// Another convenience method: call f approximately
|
|
// every deltaSeconds forever, starting deltaSeconds from now.
|
|
// To be more precise: every time f is finished, it
|
|
// is rescheduled to run deltaSeconds later. If you
|
|
// need more accurate scheduling, don't use this method.
|
|
void scheduleEvery(Function f, int64_t deltaMilliSeconds);
|
|
|
|
// To keep things as simple as possible, there is no unschedule.
|
|
|
|
// Services the queue 'forever'. Should be run in a thread,
|
|
// and interrupted using boost::interrupt_thread
|
|
void serviceQueue();
|
|
|
|
// Tell any threads running serviceQueue to stop as soon as they're
|
|
// done servicing whatever task they're currently servicing (drain=false)
|
|
// or when there is no work left to be done (drain=true)
|
|
void stop(bool drain=false);
|
|
|
|
// Returns number of tasks waiting to be serviced,
|
|
// and first and last task times
|
|
size_t getQueueInfo(boost::chrono::system_clock::time_point &first,
|
|
boost::chrono::system_clock::time_point &last) const;
|
|
|
|
// Returns true if there are threads actively running in serviceQueue()
|
|
bool AreThreadsServicingQueue() const;
|
|
|
|
private:
|
|
std::multimap<boost::chrono::system_clock::time_point, Function> taskQueue;
|
|
boost::condition_variable newTaskScheduled;
|
|
mutable boost::mutex newTaskMutex;
|
|
int nThreadsServicingQueue;
|
|
bool stopRequested;
|
|
bool stopWhenEmpty;
|
|
bool shouldStop() { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
|
|
};
|
|
|
|
/**
|
|
* Class used by CScheduler clients which may schedule multiple jobs
|
|
* which are required to be run serially. Does not require such jobs
|
|
* to be executed on the same thread, but no two jobs will be executed
|
|
* at the same time.
|
|
*/
|
|
class SingleThreadedSchedulerClient {
|
|
private:
|
|
CScheduler *m_pscheduler;
|
|
|
|
CCriticalSection m_cs_callbacks_pending;
|
|
std::list<std::function<void (void)>> m_callbacks_pending;
|
|
bool m_are_callbacks_running = false;
|
|
|
|
void MaybeScheduleProcessQueue();
|
|
void ProcessQueue();
|
|
|
|
public:
|
|
SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
|
|
void AddToProcessQueue(std::function<void (void)> func);
|
|
|
|
// Processes all remaining queue members on the calling thread, blocking until queue is empty
|
|
// Must be called after the CScheduler has no remaining processing threads!
|
|
void EmptyQueue();
|
|
};
|
|
|
|
#endif
|