mirror of
https://github.com/Zygo/bees.git
synced 2025-06-16 17:46:16 +02:00
task: serialize Task execution when Tasks block due to mutex contention
Quite often we want to execute task B after task A finishes executing, especially if tasks A and B attempt to acquire locks on the same objects. Implement that capability in Task directly: each Task holds a queue of Tasks which will be executed strictly after this Task has finished executing, or if the Task is destroyed. Add a local queue to each TaskConsumer. This queue contains a list of Tasks which are to be executed by a single thread in sequential order. These tasks are executed before fetching any tasks from TaskMaster. Each time a Task finishes executing, the list of tasks appended to the recently executed Task are spliced at the beginning of the thread's TaskConsumer local queue. These tasks will be executed in the same thread in the same order they were appended to the recently executed Task. If a Task is destroyed with a post-execution queue, that queue is also inserted at the front of the current TaskConsumer's local queue. If a Task is destroyed or somehow executed outside of a TaskConsumer thread, or a TaskConsumer thread is destroyed, the local queue of Tasks is wrapped in a "rescue_task" Task, and spliced before the head of the global queue. This preserves the sequential ordering of tasks. In all cases the order of sequential execution of Tasks that are appended to another Task is preserved. The unused queue insertion functions are removed. Exclusion is now simply a mutex, a bool, and a Task with an empty function. Tasks that queue up waiting for the mutex are stored in Exclusion's Task, and Exclusion simply runs that task when the ExclusionState is released. Signed-off-by: Zygo Blaxell <bees@furryterror.org>
This commit is contained in:
@ -27,16 +27,7 @@ namespace crucible {
|
||||
/// Create Task object containing closure and description.
|
||||
Task(string title, function<void()> exec_fn);
|
||||
|
||||
/// Insert at tail of queue (default).
|
||||
void queue_at_tail() const;
|
||||
|
||||
/// Insert at head of queue instead of tail.
|
||||
/// May insert onto current thread/CPU core's queue.
|
||||
void queue_at_head() const;
|
||||
|
||||
// Add other insertion points here (same CPU, time delay, etc).
|
||||
|
||||
/// Schedule Task at designated queue position.
|
||||
/// Schedule Task for at least one future execution.
|
||||
/// May run Task in current thread or in other thread.
|
||||
/// May run Task before or after returning.
|
||||
///
|
||||
@ -46,6 +37,9 @@ namespace crucible {
|
||||
/// task after the currently running instance returns.
|
||||
void run() const;
|
||||
|
||||
/// Schedule Task to run after this task has run at least once.
|
||||
void append(const Task &task) const;
|
||||
|
||||
/// Describe Task as text.
|
||||
string title() const;
|
||||
|
||||
@ -159,7 +153,7 @@ namespace crucible {
|
||||
|
||||
Exclusion(shared_ptr<ExclusionState> pes);
|
||||
public:
|
||||
Exclusion();
|
||||
Exclusion(const string &title);
|
||||
|
||||
// Attempt to obtain a Lock. If successful, current Task
|
||||
// owns the Lock until the ExclusionLock is released
|
||||
@ -172,9 +166,8 @@ namespace crucible {
|
||||
ExclusionLock try_lock();
|
||||
|
||||
// Execute Task when Exclusion is unlocked (possibly
|
||||
// immediately). First Task is scheduled at head,
|
||||
// all others are scheduled at tail.
|
||||
void insert_task(Task t);
|
||||
// immediately).
|
||||
void insert_task(Task t = Task::current_task());
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user