2017-03-18 00:05:10 +00:00
|
|
|
#include <ostd/io.hh>
|
|
|
|
#include <ostd/concurrency.hh>
|
|
|
|
|
|
|
|
using namespace ostd;
|
|
|
|
|
2017-03-19 15:38:30 +00:00
|
|
|
int main() {
|
2017-03-20 23:27:20 +00:00
|
|
|
/* have an array, split it in two halves and sum each half in a separate
|
|
|
|
* task, which may or may not run in parallel with the other one depending
|
|
|
|
* on the scheduler currently in use - several schedulers are shown
|
|
|
|
*/
|
2017-03-23 10:35:23 +00:00
|
|
|
auto foo = []() {
|
2017-03-30 23:14:22 +00:00
|
|
|
auto arr = { 150, 38, 76, 25, 67, 18, -15, 215, 25, -10 };
|
2017-03-19 15:38:30 +00:00
|
|
|
|
2017-03-23 10:35:23 +00:00
|
|
|
auto c = make_channel<int>();
|
2017-03-19 15:38:30 +00:00
|
|
|
auto f = [](auto c, auto half) {
|
|
|
|
c.put(foldl(half, 0));
|
|
|
|
};
|
2017-03-30 23:14:22 +00:00
|
|
|
spawn(f, c, iter(arr).slice(0, arr.size() / 2));
|
2017-04-01 14:49:38 +00:00
|
|
|
spawn(f, c, iter(arr).slice(arr.size() / 2));
|
2017-03-19 15:38:30 +00:00
|
|
|
|
2017-03-22 19:01:21 +00:00
|
|
|
int a = c.get();
|
|
|
|
int b = c.get();
|
2017-03-19 15:38:30 +00:00
|
|
|
writefln("%s + %s = %s", a, b, a + b);
|
2017-03-18 00:05:10 +00:00
|
|
|
};
|
|
|
|
|
2017-03-20 23:27:20 +00:00
|
|
|
/* using thread_scheduler results in an OS thread spawned per task,
|
|
|
|
* implementing a 1:1 (kernel-level) scheduling - very expensive on
|
|
|
|
* Windows, less expensive on Unix-likes (but more than coroutines)
|
|
|
|
*/
|
2017-03-23 12:25:18 +00:00
|
|
|
thread_scheduler{}.start([&foo]() {
|
2017-03-20 23:27:20 +00:00
|
|
|
writeln("(1) 1:1 scheduler: starting...");
|
2017-03-23 10:35:23 +00:00
|
|
|
foo();
|
2017-03-20 23:27:20 +00:00
|
|
|
writeln("(1) 1:1 scheduler: finishing...");
|
2017-03-19 13:11:23 +00:00
|
|
|
});
|
2017-03-20 23:27:20 +00:00
|
|
|
writeln();
|
2017-03-19 13:11:23 +00:00
|
|
|
|
2017-03-20 23:27:20 +00:00
|
|
|
/* using simple_coroutine_scheduler results in a coroutine spawned
|
|
|
|
* per task, implementing N:1 (user-level) scheduling - very cheap
|
|
|
|
* and portable everywhere but obviously limited to only one thread
|
|
|
|
*/
|
2017-03-23 12:25:18 +00:00
|
|
|
simple_coroutine_scheduler{}.start([&foo]() {
|
2017-03-20 23:27:20 +00:00
|
|
|
writeln("(2) N:1 scheduler: starting...");
|
2017-03-23 10:35:23 +00:00
|
|
|
foo();
|
2017-03-20 23:27:20 +00:00
|
|
|
writeln("(2) N:1 scheduler: finishing...");
|
|
|
|
});
|
|
|
|
writeln();
|
|
|
|
|
|
|
|
/* using coroutine_scheduler results in a coroutine spawned per
|
|
|
|
* task, but mapped onto a certain number of OS threads, implementing
|
|
|
|
* a hybrid M:N approach - this benefits from multicore systems and
|
|
|
|
* also is relatively cheap (you can create a big number of tasks)
|
|
|
|
*/
|
2017-03-23 12:25:18 +00:00
|
|
|
coroutine_scheduler{}.start([&foo]() {
|
2017-03-20 23:27:20 +00:00
|
|
|
writeln("(3) M:N scheduler: starting...");
|
2017-03-23 10:35:23 +00:00
|
|
|
foo();
|
2017-03-20 23:27:20 +00:00
|
|
|
writeln("(3) M:N scheduler: finishing...");
|
2017-03-18 00:05:10 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-03-20 23:27:20 +00:00
|
|
|
(1) 1:1 scheduler: starting...
|
2017-03-19 15:38:30 +00:00
|
|
|
356 + 233 = 589
|
2017-03-20 23:27:20 +00:00
|
|
|
(1) 1:1 scheduler: finishing...
|
|
|
|
|
|
|
|
(2) N:1 scheduler: starting...
|
|
|
|
356 + 233 = 589
|
|
|
|
(2) N:1 scheduler: finishing...
|
|
|
|
|
|
|
|
(3) M:N scheduler: starting...
|
2017-03-19 15:38:30 +00:00
|
|
|
356 + 233 = 589
|
2017-03-20 23:27:20 +00:00
|
|
|
(3) M:N scheduler: finishing...
|
2017-03-18 00:05:10 +00:00
|
|
|
*/
|