-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaskStealingDeque.cppm
More file actions
93 lines (75 loc) · 3.07 KB
/
TaskStealingDeque.cppm
File metadata and controls
93 lines (75 loc) · 3.07 KB
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
89
90
91
92
93
// Copyright (C) 2026 mxreal64
//
// This program 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.
//
// This program 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://gnu.org>.
export module TaskStealingDeque;
import std;
export template <typename TaskType, std::size_t Capacity>
class TaskStealingDeque {
private:
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two.");
static constexpr std::size_t Mask = Capacity - 1;
alignas(64) TaskType storage_[Capacity];
alignas(64) std::atomic<int64_t> head_{0};
alignas(64) std::atomic<int64_t> tail_{0};
public:
TaskStealingDeque() noexcept = default;
~TaskStealingDeque() = default;
TaskStealingDeque(const TaskStealingDeque&) = delete;
TaskStealingDeque& operator=(const TaskStealingDeque&) = delete;
TaskStealingDeque(TaskStealingDeque&&) = delete;
TaskStealingDeque& operator=(TaskStealingDeque&&) = delete;
bool push(TaskType&& task) noexcept {
int64_t h = head_.load(std::memory_order_relaxed);
int64_t t = tail_.load(std::memory_order_acquire);
if ((h - t) >= static_cast<int64_t>(Capacity)) {
return false;
}
storage_[h & Mask] = std::move(task);
head_.store(h + 1, std::memory_order_release);
return true;
}
bool pop(TaskType& task) noexcept {
int64_t h = head_.load(std::memory_order_relaxed) - 1;
head_.store(h, std::memory_order_seq_cst);
int64_t t = tail_.load(std::memory_order_seq_cst);
if (t <= h) {
if (t == h) {
if (!tail_.compare_exchange_strong(t, t + 1, std::memory_order_seq_cst, std::memory_order_seq_cst)) {
head_.store(h + 1, std::memory_order_release);
return false;
}
task = std::move(storage_[h & Mask]);
head_.store(h + 1, std::memory_order_release);
return true;
}
task = std::move(storage_[h & Mask]);
return true;
}
head_.store(h + 1, std::memory_order_release);
return false;
}
bool steal(TaskType& task) noexcept {
while (true) {
int64_t t = tail_.load(std::memory_order_seq_cst);
int64_t h = head_.load(std::memory_order_seq_cst);
if (t >= h) {
return false;
}
if (tail_.compare_exchange_strong(t, t + 1, std::memory_order_seq_cst, std::memory_order_seq_cst)) {
task = std::move(storage_[t & Mask]);
return true;
}
}
}
};