mirror of
https://github.com/Zygo/bees.git
synced 2025-05-17 13:25:45 +02:00
task: replace waiting state with run/exec counter
Task::run() would schedule a new execution of Task, unless it was waiting on a queue for execution. This cannot be implemented with a bool, since a Task might be included in multiple queues, and should still be in waiting state even when executed in that case. Replace the bool with a counter. run() and append() (but not append_nolock) increment the counter, exec() decrements the counter. If the counter is non-zero when run() or append() is called, the Task is not scheduled. Signed-off-by: Zygo Blaxell <bees@furryterror.org>
This commit is contained in:
parent
d5ff35eacf
commit
0928362aab
@ -27,17 +27,20 @@ namespace crucible {
|
|||||||
/// Create Task object containing closure and description.
|
/// Create Task object containing closure and description.
|
||||||
Task(string title, function<void()> exec_fn);
|
Task(string title, function<void()> exec_fn);
|
||||||
|
|
||||||
/// Schedule Task for at least one future execution.
|
/// Schedule Task for at most one future execution.
|
||||||
/// May run Task in current thread or in other thread.
|
/// May run Task in current thread or in other thread.
|
||||||
/// May run Task before or after returning.
|
/// May run Task before or after returning.
|
||||||
|
/// Schedules Task at the end of the global execution queue.
|
||||||
///
|
///
|
||||||
/// Only one instance of a Task may execute at a time.
|
/// Only one instance of a Task may execute at a time.
|
||||||
/// If a Task is already scheduled, run() does nothing.
|
/// If a Task is already scheduled, run() does nothing.
|
||||||
/// If a Task is already running, run() reschedules the
|
/// If a Task is already running when a new instance reaches
|
||||||
/// task after the currently running instance returns.
|
/// the front of the queue, the new instance will execute
|
||||||
|
/// after the current instance exits.
|
||||||
void run() const;
|
void run() const;
|
||||||
|
|
||||||
/// Schedule Task to run after this task has run at least once.
|
/// Schedule Task to run after this Task has run or
|
||||||
|
/// been destroyed.
|
||||||
void append(const Task &task) const;
|
void append(const Task &task) const;
|
||||||
|
|
||||||
/// Describe Task as text.
|
/// Describe Task as text.
|
||||||
|
48
lib/task.cc
48
lib/task.cc
@ -54,9 +54,8 @@ namespace crucible {
|
|||||||
/// Tasks to be executed after the current task is executed
|
/// Tasks to be executed after the current task is executed
|
||||||
list<TaskStatePtr> m_post_exec_queue;
|
list<TaskStatePtr> m_post_exec_queue;
|
||||||
|
|
||||||
/// Set when task is waiting to execute.
|
/// Incremented by run() and append(). Decremented by exec().
|
||||||
/// Cleared when exec() begins.
|
size_t m_run_count = 0;
|
||||||
bool m_is_waiting = false;
|
|
||||||
|
|
||||||
/// Set when task starts execution by exec().
|
/// Set when task starts execution by exec().
|
||||||
/// Cleared when exec() ends.
|
/// Cleared when exec() ends.
|
||||||
@ -95,15 +94,16 @@ namespace crucible {
|
|||||||
~TaskState();
|
~TaskState();
|
||||||
TaskState(string title, function<void()> exec_fn);
|
TaskState(string title, function<void()> exec_fn);
|
||||||
|
|
||||||
/// Run the task at least once. If task is already running, appends
|
/// Run the task at most one more time. If task has
|
||||||
/// a self-reference to its after queue. If task is not running
|
/// already started running, a new instance is scheduled.
|
||||||
/// and task is not waiting, adds task to a master queue and marks
|
/// If an instance is already scheduled by run() or
|
||||||
/// the task waiting.
|
/// append(), does nothing. Otherwise, schedules a new
|
||||||
|
/// instance at the end of TaskMaster's global queue.
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
/// Execute task immediately in current thread if it is not already
|
/// Execute task immediately in current thread if it is not already
|
||||||
/// executing in another thread. If m_run_again is set while m_is_running
|
/// executing in another thread; otherwise, append the current task
|
||||||
/// is true, the thread that set m_is_running will requeue the task.
|
/// to itself to be executed immediately in the other thread.
|
||||||
void exec();
|
void exec();
|
||||||
|
|
||||||
/// Return title of task.
|
/// Return title of task.
|
||||||
@ -112,9 +112,8 @@ namespace crucible {
|
|||||||
/// Return ID of task.
|
/// Return ID of task.
|
||||||
TaskId id() const;
|
TaskId id() const;
|
||||||
|
|
||||||
/// Queue task to execute after current task finishes executing.
|
/// Queue task to execute after current task finishes executing
|
||||||
/// If current task is neither running nor waiting, this
|
/// or is destroyed.
|
||||||
/// places the argument task on a worker queue immediately.
|
|
||||||
void append(const TaskStatePtr &task);
|
void append(const TaskStatePtr &task);
|
||||||
|
|
||||||
/// How masy Tasks are there? Good for catching leaks
|
/// How masy Tasks are there? Good for catching leaks
|
||||||
@ -204,7 +203,6 @@ namespace crucible {
|
|||||||
// then push it to the front of the global queue using normal locking methods.
|
// then push it to the front of the global queue using normal locking methods.
|
||||||
TaskStatePtr rescue_task(make_shared<TaskState>("rescue_task", [](){}));
|
TaskStatePtr rescue_task(make_shared<TaskState>("rescue_task", [](){}));
|
||||||
swap(rescue_task->m_post_exec_queue, queue);
|
swap(rescue_task->m_post_exec_queue, queue);
|
||||||
rescue_task->m_is_waiting;
|
|
||||||
TaskQueue tq_one { rescue_task };
|
TaskQueue tq_one { rescue_task };
|
||||||
TaskMasterState::push_front(tq_one);
|
TaskMasterState::push_front(tq_one);
|
||||||
}
|
}
|
||||||
@ -259,18 +257,19 @@ namespace crucible {
|
|||||||
void
|
void
|
||||||
TaskState::append_nolock(const TaskStatePtr &task)
|
TaskState::append_nolock(const TaskStatePtr &task)
|
||||||
{
|
{
|
||||||
task->m_is_waiting = true;
|
THROW_CHECK0(invalid_argument, task);
|
||||||
m_post_exec_queue.push_back(task);
|
m_post_exec_queue.push_back(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TaskState::append(const TaskStatePtr &task)
|
TaskState::append(const TaskStatePtr &task)
|
||||||
{
|
{
|
||||||
if (!task) {
|
THROW_CHECK0(invalid_argument, task);
|
||||||
return;
|
|
||||||
}
|
|
||||||
PairLock lock(m_mutex, task->m_mutex);
|
PairLock lock(m_mutex, task->m_mutex);
|
||||||
append_nolock(task);
|
if (!task->m_run_count) {
|
||||||
|
++task->m_run_count;
|
||||||
|
append_nolock(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -280,11 +279,11 @@ namespace crucible {
|
|||||||
THROW_CHECK0(invalid_argument, !m_title.empty());
|
THROW_CHECK0(invalid_argument, !m_title.empty());
|
||||||
|
|
||||||
unique_lock<mutex> lock(m_mutex);
|
unique_lock<mutex> lock(m_mutex);
|
||||||
m_is_waiting = false;
|
|
||||||
if (m_is_running) {
|
if (m_is_running) {
|
||||||
append_nolock(shared_from_this());
|
append_nolock(shared_from_this());
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
--m_run_count;
|
||||||
m_is_running = true;
|
m_is_running = true;
|
||||||
}
|
}
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
@ -327,10 +326,11 @@ namespace crucible {
|
|||||||
TaskState::run()
|
TaskState::run()
|
||||||
{
|
{
|
||||||
unique_lock<mutex> lock(m_mutex);
|
unique_lock<mutex> lock(m_mutex);
|
||||||
if (!m_is_waiting) {
|
if (m_run_count) {
|
||||||
TaskMasterState::push_back(shared_from_this());
|
return;
|
||||||
m_is_waiting = true;
|
|
||||||
}
|
}
|
||||||
|
++m_run_count;
|
||||||
|
TaskMasterState::push_back(shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskMasterState::TaskMasterState(size_t thread_max) :
|
TaskMasterState::TaskMasterState(size_t thread_max) :
|
||||||
@ -636,9 +636,7 @@ namespace crucible {
|
|||||||
Task::append(const Task &that) const
|
Task::append(const Task &that) const
|
||||||
{
|
{
|
||||||
THROW_CHECK0(runtime_error, m_task_state);
|
THROW_CHECK0(runtime_error, m_task_state);
|
||||||
if (!that) {
|
THROW_CHECK0(runtime_error, that);
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_task_state->append(that.m_task_state);
|
m_task_state->append(that.m_task_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user