=================== How-To use tasklets =================== So, threads are single-use things, right? You create them, start them, stop them, and then you need to create a new one. It makes sense, of course, but it can be a little awkward. You may want to have something that runs for a while, you stop it, but then you want to restart it. Using the standard library thread interface, you need recreate a thread object here. If you want the thread to sleep and wake up, you need to pass it some kind of condition, and a flag whether it's still alive. And to access the condition, you need some mutex or other. It's not complicated, but there's a bunch of boilerplate for simply running something in the background. Sometimes it's nice to have something a little more durable. Like a task, but lighter weight. How about calling it a ``tasklet``? .. sourcecode:: cpp :linenos: :dedent: :caption: Tasklet function #include using namespace liberate::concurrency; void my_task(tasklet::context & ctx) { while (ctx.running) { // Do your thing, then sleep ctx.sleep(std::chrono::milliseconds{20}); } } You implement a tasklet in a simple function that accepts a tasklet :cpp:struct:`liberate::concurrency::tasklet::context`; this context contains: #. An atomic boolean flag whether the tasklet is still running. #. A sleep function for putting the tasklet to sleep. This is interruptible, of course. Note that the function can, of course, be bound to some object's member function. We're just keeping it simple for here and now. With that, we can create a restartable :cpp:class:`liberate::concurrency::tasklet`: .. sourcecode:: cpp :linenos: :dedent: :caption: Tasklet management tasklet t{my_task}; t.start(); // does stuff t.stop(); // stops doing stuff t.wait(); // wait for thread to finish t.start(); // starts again t.wakeup(); // wake task up if it sleeps That's pretty much all there is. It should be clear from context that once you call ``start()``, the ``running`` flag is set; when you call ``stop()`` it is unset and the sleep is interrupted. There's one more thing. Suppose you have several threads and you want them to wait on the same condition? That is supported. Instead of just creating the tasklet, you can pass it a :cpp:struct:`liberate::concurrency::tasklet::sleep_condition` pointer. .. sourcecode:: cpp :linenos: :dedent: :caption: Multiple tasklets and one condition tasklet::sleep_condition cond; tasklet t1{my_task, &cond, true}; tasklet t2{my_task, &cond, true}; Note the third argument passed to the ``tasklet`` constructor -- it immediately asks the tasklet to ``start()`` upon creation. And that's it! You now have two threads waiting on the same condition.