proxygen
|
#include <ThreadedRepeatingFunctionRunner.h>
Public Types | |
using | RepeatingFn = folly::Function< std::chrono::milliseconds() noexcept > |
Public Member Functions | |
ThreadedRepeatingFunctionRunner () | |
~ThreadedRepeatingFunctionRunner () | |
void | stop () |
void | add (std::string name, RepeatingFn f, std::chrono::milliseconds initialSleep=std::chrono::milliseconds(0)) |
size_t | size () const |
Private Member Functions | |
bool | stopImpl () |
bool | waitFor (std::chrono::milliseconds duration) noexcept |
void | executeInLoop (RepeatingFn, std::chrono::milliseconds initialSleep) noexcept |
Private Attributes | |
std::mutex | stopMutex_ |
bool | stopping_ {false} |
std::condition_variable | stopCv_ |
std::vector< std::thread > | threads_ |
For each function fn
you add to this object, fn
will be run in a loop in its own thread, with the thread sleeping between invocations of fn
for the duration returned by fn
's previous run.
To clean up these threads, invoke stop()
, which will interrupt sleeping threads. stop()
will wait for already-running functions to return.
== Alternatives ==
If you want to multiplex multiple functions on the same thread, you can either use EventBase with AsyncTimeout objects, or FunctionScheduler for a slightly simpler API.
== Thread-safety ==
This type follows the common rule that: (1) const member functions are safe to call concurrently with const member functions, but (2) non-const member functions are not safe to call concurrently with any member functions.
== Pitfalls ==
Threads and classes don't mix well in C++, so you have to be very careful if you want to have ThreadedRepeatingFunctionRunner as a member of your class. A reasonable pattern looks like this:
// Your class must be final
because inheriting from a class with // threads can cause all sorts of subtle issues: // - Your base class might start threads that attempt to access derived // class state before that state was constructed. // - Your base class's destructor will only be able to stop threads // after the derived class state was destroyed – and that state // might be accessed by the threads. // In short, any derived class would have to do work to manage the // threads itself, which makes inheritance a poor means of composition. struct MyClass final { // Note that threads are NOT added in the constructor, for two reasons: // // (1) If you first added some threads, and then had additional // initialization (e.g. derived class constructors), this
might // not be fully constructed by the time the function threads // started running, causing heisenbugs. // // (2) If your constructor threw after thread creation, the class // destructor would not be invoked, potentially leaving the // threads running too long. // // It is much safer to have explicit two-step initialization, or to // lazily add threads the first time they are needed. MyClass() : count_(0) {}
// You must stop the threads as early as possible in the destruction // process (or even before). If MyClass had derived classes, the final // derived class MUST always call stop() as the first thing in its // destructor – otherwise, the worker threads might access already- // destroyed state. ~MyClass() { threads_.stop(); // Stop threads BEFORE destroying any state they use. }
// See the constructor for why two-stage initialization is preferred. void init() { threads_.add(bind(&MyClass::incrementCount, this)); }
std::chrono::milliseconds incrementCount() { ++count_; return 10; }
private: std::atomic<int> count_; // CAUTION: Declare last since the threads access other members of this
. ThreadedRepeatingFunctionRunner threads_; };
Definition at line 104 of file ThreadedRepeatingFunctionRunner.h.
using folly::ThreadedRepeatingFunctionRunner::RepeatingFn = folly::Function<std::chrono::milliseconds() noexcept> |
Definition at line 107 of file ThreadedRepeatingFunctionRunner.h.
folly::ThreadedRepeatingFunctionRunner::ThreadedRepeatingFunctionRunner | ( | ) |
Definition at line 24 of file ThreadedRepeatingFunctionRunner.cpp.
folly::ThreadedRepeatingFunctionRunner::~ThreadedRepeatingFunctionRunner | ( | ) |
Definition at line 26 of file ThreadedRepeatingFunctionRunner.cpp.
References stopImpl().
void folly::ThreadedRepeatingFunctionRunner::add | ( | std::string | name, |
RepeatingFn | f, | ||
std::chrono::milliseconds | initialSleep = std::chrono::milliseconds(0) |
||
) |
Run your noexcept function f
in a background loop, sleeping between calls for a duration returned by f
. Optionally waits for initialSleep
before calling f
for the first time. Names the thread using up to the first 15 chars of name
.
DANGER: If a non-final class has a ThreadedRepeatingFunctionRunner member (which, by the way, must be declared last in the class), then you must not call add() in your constructor. Otherwise, your thread risks accessing uninitialized data belonging to a child class. To avoid this design bug, prefer to use two-stage initialization to start your threads.
Definition at line 56 of file ThreadedRepeatingFunctionRunner.cpp.
References executeInLoop(), folly::gen::move, folly::setThreadName(), and threads_.
|
privatenoexcept |
Definition at line 79 of file ThreadedRepeatingFunctionRunner.cpp.
References waitFor().
Referenced by add(), and size().
|
inline |
Definition at line 138 of file ThreadedRepeatingFunctionRunner.h.
References executeInLoop(), folly::pushmi::__adl::noexcept(), stopImpl(), threads_, and waitFor().
void folly::ThreadedRepeatingFunctionRunner::stop | ( | ) |
Ideally, you will call this before initiating the destruction of the host object. Otherwise, this should be the first thing in the destruction sequence. If it comes any later, worker threads may access class state that had already been destroyed.
Definition at line 37 of file ThreadedRepeatingFunctionRunner.cpp.
References stopImpl().
|
private |
Definition at line 41 of file ThreadedRepeatingFunctionRunner.cpp.
References folly::lock(), stopCv_, stopMutex_, stopping_, folly::pushmi::detail::t, and threads_.
Referenced by size(), stop(), and ~ThreadedRepeatingFunctionRunner().
|
privatenoexcept |
Definition at line 69 of file ThreadedRepeatingFunctionRunner.cpp.
References folly::lock(), now(), stopCv_, stopMutex_, and stopping_.
Referenced by executeInLoop(), and size().
|
private |
Definition at line 157 of file ThreadedRepeatingFunctionRunner.h.
Referenced by stopImpl(), and waitFor().
|
private |
Definition at line 155 of file ThreadedRepeatingFunctionRunner.h.
Referenced by stopImpl(), and waitFor().
|
private |
Definition at line 156 of file ThreadedRepeatingFunctionRunner.h.
Referenced by stopImpl(), and waitFor().
|
private |
Definition at line 159 of file ThreadedRepeatingFunctionRunner.h.
Referenced by add(), size(), and stopImpl().