Skip to content

Commit 8a014af

Browse files
Merge pull request #9 from mcpplibs/refactor-unified-concurrent-access-interface
Enhance concurrency strategy with traits, tests, and documentation
2 parents 539af74 + 6e14d3d commit 8a014af

File tree

10 files changed

+590
-71
lines changed

10 files changed

+590
-71
lines changed

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,29 @@ auto maybe = x + y; // std::expected<primitive<int, policy::error::expected>, po
5151
- `policy::value::{checked, unchecked, saturating}`
5252
- `policy::type::{strict, compatible, transparent}`
5353
- `policy::error::{throwing, expected, terminate}`
54-
- `policy::concurrency::{none, atomic}`
54+
- `policy::concurrency::{none, fenced, fenced_relaxed, fenced_acq_rel, fenced_seq_cst}`
55+
56+
并发策略说明:
57+
58+
- `fenced*` 系列是操作级并发语义,通过策略注入内存序 fence;
59+
- `primitive` 存储仍保持统一、零开销布局,不引入额外存储层抽象;
60+
- `primitive::load/store/compare_exchange` 由并发策略的协议实现提供,若策略未实现该协议会在编译期报错。
61+
62+
示例(并发访问 API):
63+
64+
```cpp
65+
using shared_t = primitive<int, policy::value::checked,
66+
policy::concurrency::fenced_acq_rel,
67+
policy::error::expected>;
68+
69+
shared_t v{1};
70+
v.store(2);
71+
auto expected = 2;
72+
if (v.compare_exchange(expected, 3)) {
73+
auto now = v.load();
74+
(void)now;
75+
}
76+
```
5577

5678
默认策略位于 `policy::defaults`
5779

examples/ex05_concurrency_policy.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
* Example: ex05_concurrency_policy
33
*
44
* Purpose:
5-
* Demonstrate the atomic concurrency policy path under multi-threaded
5+
* Demonstrate the fenced concurrency policy path under multi-threaded
66
* repeated dispatch.
77
*
88
* Expected results:
99
* - Concurrent add operations consistently produce value 42.
10+
* - Primitive load/store/CAS APIs work under fenced policy.
1011
* - mismatch_count remains zero after all worker threads join.
1112
* - Program prints a success message and exits with code 0.
1213
*/
@@ -21,13 +22,22 @@ import mcpplibs.primitives;
2122
using namespace mcpplibs::primitives;
2223

2324
int main() {
24-
// Point 5: Use atomic concurrency policy and verify concurrent consistency.
25-
using atomic_t =
26-
primitive<int, policy::value::checked, policy::concurrency::atomic,
25+
// Point 5: Use fenced concurrency policy and verify concurrent consistency.
26+
using fenced_t =
27+
primitive<int, policy::value::checked, policy::concurrency::fenced,
2728
policy::error::expected>;
2829

29-
auto const lhs = atomic_t{12};
30-
auto const rhs = atomic_t{30};
30+
auto const lhs = fenced_t{12};
31+
auto const rhs = fenced_t{30};
32+
33+
auto concurrent_value = fenced_t{1};
34+
concurrent_value.store(2);
35+
auto expected = 2;
36+
if (!concurrent_value.compare_exchange(expected, 3) ||
37+
concurrent_value.load() != 3) {
38+
std::cerr << "fenced load/store/CAS mismatch\n";
39+
return 1;
40+
}
3141

3242
std::atomic<int> mismatch_count{0};
3343
std::vector<std::thread> workers;
@@ -51,7 +61,7 @@ int main() {
5161

5262
// A non-zero mismatch count indicates unexpected behavior under concurrency.
5363
if (mismatch_count.load(std::memory_order_relaxed) != 0) {
54-
std::cerr << "atomic policy path mismatch\n";
64+
std::cerr << "fenced policy path mismatch\n";
5565
return 1;
5666
}
5767

examples/ex07_custom_policy.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
* - Program prints a success message and exits with code 0.
1313
*/
1414

15+
#include <atomic>
1516
#include <expected>
1617
#include <iostream>
1718
#include <type_traits>
1819

20+
1921
import mcpplibs.primitives;
2022
import mcpplibs.primitives.operations.invoker;
2123

@@ -79,6 +81,8 @@ struct mcpplibs::primitives::policy::concurrency::handler<
7981
injection_type out{};
8082
out.fence_before = true;
8183
out.fence_after = false;
84+
out.order_before = std::memory_order_acquire;
85+
out.order_after = std::memory_order_relaxed;
8286
return out;
8387
}
8488
};

src/operations/invoker.cppm

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,13 +365,14 @@ constexpr auto make_div_zero(char const *reason)
365365
return make_error<CommonRep>(policy::error::kind::divide_by_zero, reason);
366366
}
367367

368-
constexpr auto apply_runtime_fence(bool enabled) noexcept -> void {
368+
constexpr auto apply_runtime_fence(bool enabled,
369+
std::memory_order order) noexcept -> void {
369370
if (!enabled) {
370371
return;
371372
}
372373

373374
if (!std::is_constant_evaluated()) {
374-
std::atomic_thread_fence(std::memory_order_seq_cst);
375+
std::atomic_thread_fence(order);
375376
}
376377
}
377378

@@ -660,12 +661,12 @@ constexpr auto run_value(CommonRep lhs, CommonRep rhs,
660661
op_binding_available<OpTag, ValuePolicy, CommonRep>,
661662
"Missing operation binding specialization for this OpTag/common type");
662663

663-
details::apply_runtime_fence(injection.fence_before);
664+
details::apply_runtime_fence(injection.fence_before, injection.order_before);
664665

665666
auto decision = op_binding<OpTag, ValuePolicy, CommonRep>::apply(lhs, rhs);
666667
auto finalized = ValueHandler::finalize(std::move(decision), injection);
667668

668-
details::apply_runtime_fence(injection.fence_after);
669+
details::apply_runtime_fence(injection.fence_after, injection.order_after);
669670
return finalized;
670671
}
671672

src/policy/handler.cppm

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module;
22

3+
#include <atomic>
34
#include <concepts>
45
#include <expected>
56
#include <optional>
@@ -84,6 +85,8 @@ namespace concurrency {
8485
struct injection {
8586
bool fence_before = false;
8687
bool fence_after = false;
88+
std::memory_order order_before = std::memory_order_seq_cst;
89+
std::memory_order order_after = std::memory_order_seq_cst;
8790
};
8891

8992
template <typename Policy, typename OpTag, typename CommonRep,
@@ -94,6 +97,17 @@ struct handler {
9497
using result_type = std::expected<CommonRep, ErrorPayload>;
9598

9699
static constexpr auto inject() noexcept -> injection_type { return {}; }
100+
101+
static constexpr auto load(CommonRep const &) noexcept -> CommonRep {
102+
return CommonRep{};
103+
}
104+
105+
static constexpr auto store(CommonRep &, CommonRep) noexcept -> void {}
106+
107+
static constexpr auto compare_exchange(CommonRep &, CommonRep &,
108+
CommonRep) noexcept -> bool {
109+
return false;
110+
}
97111
};
98112

99113
template <typename Policy, typename OpTag, typename CommonRep,
@@ -126,6 +140,36 @@ concept handler_available = requires {
126140
requires handler_protocol<Policy, OpTag, CommonRep, ErrorPayload>;
127141
};
128142

143+
template <typename Policy, typename CommonRep,
144+
typename ErrorPayload = error::kind>
145+
concept handler_access_protocol = requires {
146+
requires concurrency_policy<Policy>;
147+
{
148+
handler<Policy, void, CommonRep, ErrorPayload>::enabled
149+
} -> std::convertible_to<bool>;
150+
requires handler<Policy, void, CommonRep, ErrorPayload>::enabled;
151+
{
152+
handler<Policy, void, CommonRep, ErrorPayload>::load(
153+
std::declval<CommonRep const &>())
154+
} noexcept -> std::same_as<CommonRep>;
155+
{
156+
handler<Policy, void, CommonRep, ErrorPayload>::store(
157+
std::declval<CommonRep &>(), std::declval<CommonRep>())
158+
} noexcept -> std::same_as<void>;
159+
{
160+
handler<Policy, void, CommonRep, ErrorPayload>::compare_exchange(
161+
std::declval<CommonRep &>(), std::declval<CommonRep &>(),
162+
std::declval<CommonRep>())
163+
} noexcept -> std::same_as<bool>;
164+
};
165+
166+
template <typename Policy, typename CommonRep,
167+
typename ErrorPayload = error::kind>
168+
concept handler_access_available = requires {
169+
requires handler<Policy, void, CommonRep, ErrorPayload>::enabled;
170+
requires handler_access_protocol<Policy, CommonRep, ErrorPayload>;
171+
};
172+
129173
} // namespace concurrency
130174

131175
namespace type {

0 commit comments

Comments
 (0)