YACLib
C++ library for concurrent tasks execution
Loading...
Searching...
No Matches
strand.cpp
Go to the documentation of this file.
2#include <yaclib/log.hpp>
4
5#include <utility>
6
7namespace yaclib {
8
9Strand::Strand(IExecutorPtr e) noexcept : _executor{std::move(e)} {
10}
11
13 YACLIB_DEBUG(_jobs.load(std::memory_order_relaxed) != Mark(), "Strand not empty in dtor");
14}
15
19
21 return _executor->Alive();
22}
23
24void Strand::Submit(Job& job) noexcept {
25 auto* expected = _jobs.load(std::memory_order_relaxed);
26 do {
27 job.next = expected == Mark() ? nullptr : expected;
28 } while (!_jobs.compare_exchange_weak(expected, &job, std::memory_order_acq_rel, std::memory_order_relaxed));
29 if (expected == Mark()) {
30 static_cast<Job&>(*this).IncRef();
31 _executor->Submit(*this);
32 }
33}
34
35void Strand::Call() noexcept {
36 auto* node = _jobs.exchange(nullptr, std::memory_order_acquire);
37 Node* prev = nullptr;
38 do {
39 auto* next = node->next;
40 node->next = prev;
41 prev = node;
42 node = next;
43 } while (node != nullptr);
44 do {
45 auto* next = prev->next;
46 static_cast<Job*>(prev)->Call();
47 prev = next;
48 } while (prev != nullptr);
49 if (_jobs.load(std::memory_order_relaxed) == node &&
50 _jobs.compare_exchange_strong(node, Mark(), std::memory_order_release, std::memory_order_relaxed)) {
51 static_cast<Job&>(*this).DecRef();
52 } else {
53 _executor->Submit(*this);
54 }
55}
56
57void Strand::Drop() noexcept {
58 auto* node = _jobs.exchange(Mark(), std::memory_order_acq_rel);
59 do {
60 auto* next = node->next;
61 static_cast<Job*>(node)->Drop();
62 node = next;
63 } while (node != nullptr);
64 static_cast<Job&>(*this).DecRef();
65}
66
67detail::Node* Strand::Mark() noexcept {
68 return static_cast<Node*>(this);
69}
70
72 return MakeShared<Strand>(1, std::move(e));
73}
74
75} // namespace yaclib
virtual bool Alive() const noexcept=0
Return true if executor still alive, that means job passed to submit will be Call.
virtual void Submit(Job &job) noexcept=0
Submit given job.
virtual void IncRef() noexcept
Increments reference counter.
Definition ref.hpp:13
Callable that can be executed in an IExecutor.
Definition job.hpp:12
bool Alive() const noexcept final
Return true if executor still alive, that means job passed to submit will be Call.
Definition strand.cpp:20
Type Tag() const noexcept final
Return type of this executor.
Definition strand.cpp:16
void Submit(Job &job) noexcept final
Submit given job.
Definition strand.cpp:24
~Strand() noexcept override
Definition strand.cpp:12
#define YACLIB_DEBUG(cond, message)
Definition log.hpp:84
IExecutorPtr MakeStrand(IExecutorPtr e)
Strand is the asynchronous analogue of a mutex.
Definition strand.cpp:71
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25