source: doc/papers/llheap/examples/ProdCons.cpp@ 006d4c4

Last change on this file since 006d4c4 was 7bef8cf, checked in by Peter A. Buhr <pabuhr@…>, 2 years ago

start paper on llheap

  • Property mode set to 100644
File size: 5.6 KB
Line 
1#include <cassert>
2#include <cstdlib>
3#include <iostream>
4#include <experimental/coroutine>
5#include <unistd.h>
6
7int random(int max) {
8 return std::rand() % max;
9}
10
11struct Prod;
12struct Cons;
13
14struct resumable {
15 virtual resumable * resume() = 0;
16};
17
18struct Prod : public resumable {
19 struct local {
20 Cons * c;
21 int N, money, receipt;
22 };
23
24 struct promise_type {
25 local _l;
26 resumable * next;
27
28 Prod get_return_object() {
29 return Prod(std::experimental::coroutine_handle<promise_type>::from_promise(*this));
30 }
31
32 auto initial_suspend() { return std::experimental::suspend_never(); }
33 auto final_suspend() { return std::experimental::suspend_always(); }
34
35 void return_void() {}
36 void unhandled_exception() {}
37 };
38
39 struct data {
40 promise_type * _promise = nullptr;
41 bool await_ready() noexcept { return false; }
42 void await_suspend(std::experimental::coroutine_handle<promise_type> _coroutine) noexcept {
43 _promise = &_coroutine.promise();
44 }
45 local & await_resume() noexcept { assert(_promise); return _promise->_l; }
46 };
47
48 std::experimental::coroutine_handle<promise_type> _coroutine = nullptr;
49
50 explicit Prod(std::experimental::coroutine_handle<promise_type> coroutine)
51 : _coroutine(coroutine)
52 {}
53
54 ~Prod() {
55 if(_coroutine) { _coroutine.destroy(); }
56 }
57
58 Prod() = default;
59 Prod(Prod const &) = delete;
60 Prod& operator=(Prod const &) = delete;
61
62 Prod(Prod&& other) {
63 std::swap(_coroutine, other._coroutine);
64 }
65
66 Prod& operator=(Prod&& other) {
67 if(&other != this) {
68 _coroutine = other._coroutine;
69 other._coroutine = nullptr;
70 }
71 return *this;
72 }
73
74 static Prod main();
75
76 struct payment_return;
77
78 payment_return payment(int money);
79
80 auto start(int N, Cons & c) {
81 _coroutine.promise()._l.c = &c;
82 _coroutine.promise()._l.N = N;
83 _coroutine.promise()._l.receipt = 0;
84 }
85
86 virtual resumable * resume() override final {
87 _coroutine.resume();
88 return _coroutine.promise().next;
89 }
90};
91
92struct Cons : public resumable {
93 struct local {
94 Prod * p;
95 int p1, p2, status;
96 bool done;
97 };
98
99 struct promise_type {
100 local _l;
101 resumable * next;
102
103 Cons get_return_object() {
104 return Cons(std::experimental::coroutine_handle<promise_type>::from_promise(*this));
105 }
106
107 auto initial_suspend() { return std::experimental::suspend_never(); }
108 auto final_suspend() { return std::experimental::suspend_always(); }
109
110 void return_void() {}
111 void unhandled_exception() {}
112 };
113
114 struct data {
115 Prod * _p;
116 data(Prod & prod) : _p(&prod) {}
117 promise_type * _promise = nullptr;
118 bool await_ready() noexcept { return false; }
119 void await_suspend(std::experimental::coroutine_handle<promise_type> _coroutine) noexcept {
120 _promise = &_coroutine.promise();
121 }
122 local & await_resume() noexcept { assert(_promise); _promise->_l.p = _p; return _promise->_l; }
123 };
124
125 std::experimental::coroutine_handle<promise_type> _coroutine = nullptr;
126
127 explicit Cons(std::experimental::coroutine_handle<promise_type> coroutine)
128 : _coroutine(coroutine)
129 {}
130
131 ~Cons() {
132 if(_coroutine) { _coroutine.destroy(); }
133 }
134
135 Cons() = default;
136 Cons(Cons const &) = delete;
137 Cons& operator=(Cons const &) = delete;
138
139 Cons(Cons&& other) {
140 std::swap(_coroutine, other._coroutine);
141 }
142
143 Cons& operator=(Cons&& other) {
144 if(&other != this) {
145 _coroutine = other._coroutine;
146 other._coroutine = nullptr;
147 }
148 return *this;
149 }
150
151 static Cons main( Prod & prod );
152
153 auto deliver(int p1, int p2) {
154 _coroutine.promise()._l.p1 = p1;
155 _coroutine.promise()._l.p2 = p2;
156
157 struct ret {
158 int _status;
159 Cons * c;
160 bool await_ready() { return false; }
161 void await_suspend(std::experimental::coroutine_handle<Prod::promise_type> _coroutine) {
162 _coroutine.promise().next = c;
163 }
164 int await_resume() { return _status; }
165 };
166 return ret{ _coroutine.promise()._l.status, this };
167 }
168
169 auto stop() {
170 _coroutine.promise()._l.done = true;
171 struct ret {
172 Cons * c;
173 Prod::promise_type * _promise;
174 bool await_ready() { return false; }
175 void await_suspend(std::experimental::coroutine_handle<Prod::promise_type> _coroutine) {
176 _promise = &_coroutine.promise();
177 _promise->next = c;
178 }
179 void await_resume() {
180 _promise->next = nullptr;
181 }
182 };
183 return ret{this, nullptr};
184 }
185
186 virtual resumable * resume() override final {
187 _coroutine.resume();
188 return _coroutine.promise().next;
189 }
190};
191
192struct Prod::payment_return {
193 int _receipt;
194 Prod * p;
195 bool await_ready() { return false; }
196 void await_suspend(std::experimental::coroutine_handle<Cons::promise_type> _coroutine) {
197 _coroutine.promise().next = p;
198 }
199 int await_resume() { return _receipt; }
200};
201
202Prod::payment_return Prod::payment(int money) {
203 _coroutine.promise()._l.money = money;
204 return payment_return{ _coroutine.promise()._l.receipt, this };
205}
206
207Prod Prod::main() {
208 auto & p = co_await Prod::data();
209 for(int i = 0; i < p.N; i++) {
210 int p1 = random(100), p2 = random(100);
211 std::cout << p1 << " " << p2 << std::endl;
212 int status = co_await p.c->deliver(p1, p2);
213 std::cout << " $" << p.money << std::endl << status << std::endl;
214 p.receipt += 1;
215 }
216 co_await p.c->stop();
217 std::cout << "prod stops" << std::endl;
218}
219
220Cons Cons::main( Prod & prod ) {
221 auto & c = co_await Cons::data( prod );
222 int money = 1, receipt;
223 for(;!c.done ;) {
224 std::cout << c.p1 << " " << c.p2 << std::endl;
225 std::cout << " $ " << money << std::endl;
226 c.status += 1;
227 receipt = co_await c.p->payment( money );
228 std::cout << " # " << receipt << std::endl;
229 money += 1;
230 }
231 std::cout << "cons stops" << std::endl;
232}
233
234void dispatch(resumable * r) {
235 while((r = r->resume()));
236}
237
238int main() {
239 auto prod = Prod::main();
240 auto cons = Cons::main( prod );
241 srandom( getpid() );
242 prod.start(5, cons);
243 dispatch(&prod);
244}
Note: See TracBrowser for help on using the repository browser.