File: TaskQueue.h

package info (click to toggle)
endless-sky 0.10.16-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 414,608 kB
  • sloc: cpp: 73,435; python: 893; xml: 666; sh: 271; makefile: 28
file content (88 lines) | stat: -rw-r--r-- 2,888 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* TaskQueue.h
Copyright (c) 2022 by Michael Zahniser

Endless Sky is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.

Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

#include <functional>
#include <future>
#include <list>
#include <mutex>
#include <queue>



// Class for queuing up tasks that are to be executed in parallel by using
// every thread available on the executing CPU.
// The queue is also responsible to execute follow-up tasks that need to
// executed after the async task, for example uploading a loaded to the GPU
// (which needs to happen on the main thread on OpenGL).
class TaskQueue {
public:
	// An internal structure representing a task to execute.
	struct Task {
		TaskQueue *queue;

		// The function to execute in parallel.
		std::function<void()> async;
		// If specified, this function is called in the main thread after
		// the function above has finished executing.
		std::function<void()> sync;

		// The pointer to this task's future stored in the queue.
		std::list<std::shared_future<void>>::const_iterator futureIt;

		std::promise<void> futurePromise;
	};

	// The maximum amount of sync tasks to execute in one go.
	static constexpr int MAX_SYNC_TASKS = 100;

public:
	// Initialize the threads used to execute the tasks.
	TaskQueue() = default;
	TaskQueue(const TaskQueue &) = delete;
	TaskQueue &operator=(const TaskQueue &) = delete;
	~TaskQueue();

	// Queue a function to execute in parallel, with another optional function that
	// will get executed on the main thread after the first function finishes.
	// Returns a future representing the future result of the async call. Ignores
	// any main thread task that still need to be executed!
	std::shared_future<void> Run(std::function<void()> asyncTask, std::function<void()> syncTask = {});

	// Process any tasks to be scheduled to be executed on the main thread.
	void ProcessSyncTasks();

	// Waits for all of this queue's task to finish. Ignores any sync tasks to be processed.
	void Wait();


private:
	// Whether there are any outstanding async tasks left in this queue.
	bool IsDone() const;


public:
	// Thread entry point.
	static void ThreadLoop() noexcept;


private:
	std::list<std::shared_future<void>> futures;

	// Tasks from this queue that need to be executed on the main thread.
	std::queue<std::function<void()>> syncTasks;
	mutable std::mutex syncMutex;
};