Ensuring task execution order in threadpool

后端 未结 17 1007
情深已故
情深已故 2020-12-12 11:54

I have been reading about the thread-pool pattern and I can\'t seem to find the usual solution for the following problem.

I sometimes want tasks to be executed serial

17条回答
  •  孤街浪徒
    2020-12-12 12:42

    Basically, there are a number of pending tasks. Some of the tasks can only be performed when one or more other pending tasks have finished executing.

    The pending tasks can be modeled in a dependency graph:

    • "task 1 -> task2" means "task 2 can be executed only after task 1 is finished." the arrows point in the direction of execution order.
    • the indegree of a task (the number of tasks pointing to it) determines whether the task is ready for execution. If the indegree is 0, it can be executed.
    • sometimes a task must wait for multiple tasks to finish, the indegree is then >1.
    • if a task doesn't have to wait for other tasks to finish anymore (its indegree is zero), it can be submitted to the thread pool with worker threads, or the queue with tasks waiting to be picked up by a worker thread. You know the submitted task will not cause deadlock, because the task isn't waiting for anything. As an optimization, you can use a priority queue, e.g. in which tasks that more tasks in the dependency graph depend on will be executed first. This also can't provoke deadlock, because all tasks in the thread pool can be executed. It can provoke starvation, however.
    • If a task finishes execution, it can be removed from the dependency graph, possibly reducing the indegree of other tasks, which can in turn be submitted to the pool of working threads.

    So there is (at least) one thread used to add/remove pending tasks, and there is a thread pool of working threads.

    When a task is added to the dependency graph, you must check:

    • how the task is connected in the dependency graph: what tasks must it wait for to finish and what tasks must wait for it to finish? Draw connections from and to the new task accordingly.
    • once the connections are drawn: did the new connections cause any cycles in the dependency graph? If so, there is a deadlock situation.

    Performance:

    • this pattern is slower than sequential execution if parallel execution is in fact rarely possible, because you need extra administration to do everything almost sequentially anyway.
    • this pattern is fast if many tasks can be performed simultaneously in practice.

    Assumptions:

    As you may have read between the lines, you must design the tasks so that they don't interfere with other tasks. Also, there must be a way to determine the priority of the tasks. The task priority should include the data handled by each task. Two tasks may not alter the same object simultaneously; one of the tasks should get priority over the other one instead, or the performed operations on the object must be thread-safe.

提交回复
热议问题