Compare commits
5 Commits
dev
...
coroutines
Author | SHA1 | Date | |
---|---|---|---|
5608eab8eb | |||
d546ca9db8 | |||
ce2c22676b | |||
9965f1e1c7 | |||
aca2724e0c |
@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.10)
|
||||
project(Asynco)
|
||||
|
||||
# Postavi verziju projekta
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Pronađi Boost biblioteku (ako nije uobičajeni direktorijum, postavi put)
|
||||
|
174
README.md
174
README.md
@ -1,13 +1,13 @@
|
||||
|
||||
# Asynco
|
||||
|
||||
A C++ library for event-driven asynchronous multi-threaded programming.
|
||||
A C++ library for event-driven asynchronous multi-threaded programming that serves as a runtime for asynchronous operations. It acts as a wrapper around the Boost.Asio library, providing a cleaner way to write asynchronous, concurrent, and parallel code utilizing a set of threads and an event loops. It offers features for event-driven programming, timers, and coroutine support.
|
||||
|
||||
## Motivation
|
||||
|
||||
The original concept was to create an interface capable of asynchronously calling any function. It has since evolved into a library that incorporates a thread pool, each with its own event loop, event-driven programming, and functions inherently designed for asynchronous operation (including periodic and delayed functions).
|
||||
The initial goal was to create an interface that makes it easy and clean to asynchronously invoke any function in C++ without resorting to complex calls. Initially, the library was built around a custom implementation of a scheduling loop for queuing functions. However, this part was later replaced with Boost.Asio, mainly for its timer functionality. As the library evolved, it expanded to include a thread pool, each with its own event loop, and adopted event-driven programming. This enhancement also introduced functions specifically designed for asynchronous operations, including periodic and delayed execution.
|
||||
|
||||
The asynchronous filesystem is provided solely to guide users on how to wrap any time- or IO-intensive function for asynchronous execution.
|
||||
The asynchronous filesystem was included solely to demonstrate how users can wrap any time- or I/O-intensive functions for asynchronous execution.
|
||||
|
||||
## Features
|
||||
|
||||
@ -16,12 +16,13 @@ The asynchronous filesystem is provided solely to guide users on how to wrap any
|
||||
- Header only
|
||||
- Asynchronous programming
|
||||
- Multithread
|
||||
- Asynchronous timer functions: periodic, delayed (like setInterval and setTimeout from JS)
|
||||
- Asynchronous timer functions: Periodic, Delayed (like setInterval and setTimeout from JS)
|
||||
- Typed events (on, tick, off) (like EventEmitter from JS: on, emit, etc)
|
||||
- Event loops
|
||||
- Multiple parallel execution loops
|
||||
- Asynchronous file IO
|
||||
- Based on ASIO (Boost Asio)
|
||||
- On C++20 support Boost.Asio coroutines
|
||||
## Installation
|
||||
|
||||
Just download the latest release and unzip it into your project.
|
||||
@ -30,13 +31,13 @@ Just download the latest release and unzip it into your project.
|
||||
#define NUM_OF_RUNNERS 8 // To change the number of threads used by asynco, without this it runs according to the number of cores
|
||||
|
||||
#include "asynco/lib/asynco.hpp" // async_ (), await_()
|
||||
#include "asynco/lib/triggers.hpp" // trigger (event emitter)
|
||||
#include "asynco/lib/timers.hpp" // periodic, delayed (like setInterval and setTimeout from JS)
|
||||
#include "asynco/lib/triggers.hpp" // Trigger (event emitter)
|
||||
#include "asynco/lib/timers.hpp" // Periodic, Delayed (like setInterval and setTimeout from JS)
|
||||
#include "asynco/lib/filesystem.hpp" // for async read and write files
|
||||
#include "asynco/lib/define.hpp" // async_, await_, asyncable_ defines
|
||||
|
||||
using namespace marcelb;
|
||||
using namespace asynco;
|
||||
using namespace triggers;
|
||||
|
||||
// At the end of the main function, always set
|
||||
_asynco_engine.run();
|
||||
@ -46,11 +47,15 @@ return 0;
|
||||
|
||||
## Usage
|
||||
|
||||
Time asynchronous functions
|
||||
In the following sections, we will explore timers, function execution via the runtime, asynchronous invocation, and waiting for results. We will cover essential use cases involving triggers, file handling, and coroutines.
|
||||
|
||||
### Timers
|
||||
|
||||
We have two timer classes, Periodic (which runs a callback function periodically), and Delayed (delayed runs a callback function only once).
|
||||
|
||||
```c++
|
||||
// start periodic
|
||||
periodic inter1 ([]() {
|
||||
Periodic inter1 ([]() {
|
||||
cout << "Interval 1" << endl;
|
||||
}, 1000);
|
||||
|
||||
@ -64,7 +69,7 @@ int t = inter1.ticks();
|
||||
bool stoped = inter1.stoped();
|
||||
|
||||
// start delayed
|
||||
delayed time1 ( [] () {
|
||||
Delayed time1 ( [] () {
|
||||
cout << "Timeout 1 " << endl;
|
||||
}, 10000);
|
||||
|
||||
@ -77,30 +82,10 @@ int t = time1.expired();
|
||||
// is it stopped
|
||||
bool stoped = time1.stoped();
|
||||
|
||||
// If you don't want to save in a variable, but you want to start a timer, use these functions
|
||||
// And you can also save them, they are only of the shared pointer type
|
||||
|
||||
auto d = Delayed( [](){
|
||||
cout << "Delayed" << endl;
|
||||
}, 2000);
|
||||
|
||||
auto p = Periodic( [](){
|
||||
cout << "Periodic" << endl;
|
||||
}, 700);
|
||||
|
||||
Periodic( [&] (){
|
||||
cout << "Delayed expire " << d->expired() << endl;
|
||||
cout << "Periodic ticks " << p->ticks() << endl;
|
||||
cout << "Delayed stoped " << d->stoped() << endl;
|
||||
cout << "Periodic stoped " << p->stoped() << endl;
|
||||
}, 1000);
|
||||
|
||||
Delayed( [&](){
|
||||
p->stop();
|
||||
}, 10000);
|
||||
|
||||
```
|
||||
Make functions asynchronous
|
||||
### Make functions asynchronous
|
||||
|
||||
Running functions at runtime, asynchronous execution, uses the `async_` call and its return type is `std::future<T>`
|
||||
|
||||
```c++
|
||||
/**
|
||||
@ -139,12 +124,11 @@ clm classes;
|
||||
async_ ( [&classes] () {
|
||||
classes.classMethode();
|
||||
});
|
||||
```
|
||||
|
||||
To wait for the result (blocking the flow) use `await_` (basically nothing more than a `.get()` call on a future object)
|
||||
|
||||
|
||||
/**
|
||||
* await_ after runned as async
|
||||
*/
|
||||
```c++
|
||||
|
||||
auto a = async_ ( []() {
|
||||
sleep_for(2s); // only for simulating long duration function
|
||||
@ -164,10 +148,20 @@ cout << await_(async_ ( [] () {
|
||||
return 4;
|
||||
})) << endl;
|
||||
|
||||
```
|
||||
|
||||
/**
|
||||
* Await all
|
||||
**/
|
||||
If you want to run asynchronously but need the result immediately, you can use a shorter notation
|
||||
|
||||
```c++
|
||||
|
||||
await_ ([]() {
|
||||
cout << "Hello" << endl;
|
||||
});
|
||||
|
||||
```
|
||||
If multiple function calls do not depend on each other, you can call them and wait for the results later, better concurrency.
|
||||
|
||||
```c++
|
||||
|
||||
auto a = async_ ( []() {
|
||||
cout << "A" << endl;
|
||||
@ -218,13 +212,18 @@ auto await_all = [&] () {
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
Just an example:
|
||||
|
||||
```c++
|
||||
|
||||
/**
|
||||
* Sleep with delayed sleep implement
|
||||
*/
|
||||
* Sleep with delayed sleep implement
|
||||
**/
|
||||
|
||||
void sleep_to (int _time) {
|
||||
promise<void> _promise;
|
||||
delayed t( [&]() {
|
||||
Delayed t( [&]() {
|
||||
_promise.set_value();
|
||||
}, _time);
|
||||
|
||||
@ -239,7 +238,7 @@ sleep_to(3000);
|
||||
|
||||
void promise_reject (int _time) {
|
||||
promise<void> _promise;
|
||||
delayed t( [&]() {
|
||||
Delayed t( [&]() {
|
||||
try {
|
||||
// simulate except
|
||||
throw runtime_error("Error simulation");
|
||||
@ -258,16 +257,19 @@ try {
|
||||
cout<< err.what() << endl;
|
||||
}
|
||||
```
|
||||
Events
|
||||
|
||||
### Triggers
|
||||
|
||||
The library implements Triggers, which are basically typed Events.
|
||||
|
||||
```c++
|
||||
/**
|
||||
* initialization of typed events
|
||||
*/
|
||||
|
||||
trigger<int, int> ev2int;
|
||||
trigger<int, string> evintString;
|
||||
trigger<> evoid;
|
||||
Trigger<int, int> ev2int;
|
||||
Trigger<int, string> evintString;
|
||||
Trigger<> evoid;
|
||||
|
||||
ev2int.on("sum", [](int a, int b) {
|
||||
cout << "Sum " << a+b << endl;
|
||||
@ -312,14 +314,14 @@ evoid.tick("void"); // nothing is happening
|
||||
Extend own class whit events
|
||||
|
||||
```c++
|
||||
class myOwnClass : public trigger<int> {
|
||||
class myOwnClass : public Trigger<int> {
|
||||
public:
|
||||
myOwnClass() : trigger() {};
|
||||
myOwnClass() : Trigger() {};
|
||||
};
|
||||
|
||||
myOwnClass myclass;
|
||||
|
||||
delayed t( [&] {
|
||||
Delayed t( [&] {
|
||||
myclass.tick("constructed", 1);
|
||||
}, 200);
|
||||
|
||||
@ -334,8 +336,8 @@ Implementing a class with multiple triggers of different types
|
||||
```c++
|
||||
|
||||
class ClassWithTriggers {
|
||||
trigger<int> emitter1;
|
||||
trigger<string> emitter2;
|
||||
Trigger<int> emitter1;
|
||||
Trigger<string> emitter2;
|
||||
|
||||
public:
|
||||
template<typename... T>
|
||||
@ -377,7 +379,7 @@ mt.tick("string", string("Hello world"));
|
||||
|
||||
```
|
||||
|
||||
|
||||
Another example:
|
||||
Asynchronous file IO
|
||||
|
||||
```c++
|
||||
@ -419,6 +421,70 @@ try {
|
||||
|
||||
```
|
||||
|
||||
## Coroutine
|
||||
|
||||
If `define.hpp` is included, you can initialize coroutines using `asyncable<T>`; if not, just use `boost::asio::awaitable<T>`.
|
||||
|
||||
```c++
|
||||
|
||||
asyncable<int> c2(int a) {
|
||||
co_return a * 2;
|
||||
}
|
||||
|
||||
```
|
||||
To run the coroutine at runtime, simply call:
|
||||
```c++
|
||||
|
||||
async_(c2(4));
|
||||
|
||||
```
|
||||
Or using a lambda expression:
|
||||
|
||||
```c++
|
||||
|
||||
async_([]() -> asyncable<void> {
|
||||
std::cout << "Hello" << std::endl;
|
||||
co_await c2(4);
|
||||
co_return;
|
||||
}());
|
||||
|
||||
```
|
||||
To retrieve results from coroutines, you can do so as you would from classical functions by calling `await_`:
|
||||
```c++
|
||||
|
||||
int r = await_(
|
||||
async_(
|
||||
c2(10)
|
||||
));
|
||||
|
||||
```
|
||||
|
||||
If you need the result immediately, you can use a shorter notation
|
||||
|
||||
```c++
|
||||
|
||||
auto a = await_ ( c2(3));
|
||||
cout << a << endl;
|
||||
|
||||
await_ ([]() -> asyncable<void> {
|
||||
cout << "Hello" << endl;
|
||||
co_return;
|
||||
}());
|
||||
|
||||
```
|
||||
|
||||
Timers and triggers work the same with coroutines; it is important to call the coroutine with `async_` in the callback, and to call `async_`, wrap it with a lambda expression:
|
||||
|
||||
```c++
|
||||
|
||||
Periodic p([]() {
|
||||
async_(c2(34));
|
||||
}, 2000);
|
||||
|
||||
```
|
||||
If you need a result, you can also retrieve it with `await_`.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[APACHE 2.0](http://www.apache.org/licenses/LICENSE-2.0/)
|
||||
|
@ -3,9 +3,14 @@
|
||||
|
||||
#include "engine.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
#include <boost/asio/awaitable.hpp>
|
||||
#include <boost/asio/co_spawn.hpp>
|
||||
#include <boost/asio/use_awaitable.hpp>
|
||||
#endif
|
||||
|
||||
namespace marcelb {
|
||||
namespace asynco {
|
||||
|
||||
@ -19,6 +24,34 @@ auto async_(F&& f, Args&&... args) -> future<typename result_of<F(Args...)>::typ
|
||||
return res;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
/**
|
||||
* Run the coroutine
|
||||
*/
|
||||
template <typename T>
|
||||
std::future<T> async_(boost::asio::awaitable<T> _coroutine) {
|
||||
std::promise<T> promise;
|
||||
auto future = promise.get_future();
|
||||
|
||||
co_spawn(_asynco_engine.io_context, [_coroutine = std::move(_coroutine), promise = std::move(promise)]() mutable -> boost::asio::awaitable<void> {
|
||||
try {
|
||||
if constexpr (!std::is_void_v<T>) {
|
||||
T result = co_await std::move(_coroutine);
|
||||
promise.set_value(std::move(result));
|
||||
} else {
|
||||
co_await std::move(_coroutine);
|
||||
promise.set_value(); // Za void ne postavljamo rezultat
|
||||
}
|
||||
} catch (...) {
|
||||
promise.set_exception(std::current_exception()); // Postavljamo izuzetak
|
||||
}
|
||||
}, boost::asio::detached);
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Block until the asynchronous call completes
|
||||
*/
|
||||
@ -36,26 +69,53 @@ T await_(future<T>&& r) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Block until the asynchronous call completes or time expired
|
||||
* Run the function asynchronously an block until completes
|
||||
*/
|
||||
template<typename T>
|
||||
T await_(future<T>& r, uint64_t time) {
|
||||
if (r.wait_for(chrono::milliseconds(time)) == std::future_status::timeout) {
|
||||
throw runtime_error("Asynchronous execution timed out");
|
||||
}
|
||||
return r.get();
|
||||
template<class F, class... Args>
|
||||
auto await_(F&& f, Args&&... args) -> typename result_of<F(Args...)>::type {
|
||||
return await_(
|
||||
async_(f, args...)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
|
||||
/**
|
||||
* Run the coruotine and wait
|
||||
*/
|
||||
template <typename T>
|
||||
T await_(boost::asio::awaitable<T> _coroutine) {
|
||||
return await_(
|
||||
async_(
|
||||
move(_coroutine)
|
||||
));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Block until the asynchronous call completes or time expired
|
||||
*/
|
||||
template<typename T>
|
||||
T await_(future<T>&& r, uint64_t time) {
|
||||
if (r.wait_for(chrono::milliseconds(time)) == std::future_status::timeout) {
|
||||
throw runtime_error("Asynchronous execution timed out");
|
||||
}
|
||||
return move(r).get();
|
||||
}
|
||||
// template<typename T>
|
||||
// T await_(future<T>& r, uint64_t time) {
|
||||
// if (r.wait_for(chrono::milliseconds(time)) == std::future_status::timeout) {
|
||||
// throw runtime_error("Asynchronous execution timed out");
|
||||
// }
|
||||
// return r.get();
|
||||
// }
|
||||
|
||||
/**
|
||||
* Block until the asynchronous call completes or time expired
|
||||
*/
|
||||
// template<typename T>
|
||||
// T await_(future<T>&& r, uint64_t time) {
|
||||
// if (r.wait_for(chrono::milliseconds(time)) == std::future_status::timeout) {
|
||||
// throw runtime_error("Asynchronous execution timed out");
|
||||
// }
|
||||
// return move(r).get();
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,10 @@ namespace asynco {
|
||||
#define async_ marcelb::asynco::async_
|
||||
#define await_ marcelb::asynco::await_
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
#define asyncable boost::asio::awaitable
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ int64_t rtime_us();
|
||||
/**
|
||||
* Core timer class for construct time async functions
|
||||
*/
|
||||
class timer {
|
||||
class Timer {
|
||||
boost::asio::steady_timer st;
|
||||
bool _stop = false;
|
||||
bool repeate;
|
||||
@ -35,14 +35,13 @@ class timer {
|
||||
/**
|
||||
* A method to assign a callback wrapper and a reinitialization algorithm
|
||||
*/
|
||||
void init();
|
||||
|
||||
void init();
|
||||
public:
|
||||
|
||||
/**
|
||||
* The constructor creates the steady_timer and accompanying variables and runs a method to initialize the timer
|
||||
*/
|
||||
timer (function<void()> _callback, uint64_t _time, bool _repeate);
|
||||
Timer (function<void()> _callback, uint64_t _time, bool _repeate);
|
||||
|
||||
/**
|
||||
* Stop timer
|
||||
@ -68,21 +67,21 @@ class timer {
|
||||
/**
|
||||
* The destructor stops the timer
|
||||
*/
|
||||
~timer();
|
||||
~Timer();
|
||||
};
|
||||
|
||||
/**
|
||||
* Class periodic for periodic execution of the callback in time in ms
|
||||
*/
|
||||
class periodic {
|
||||
shared_ptr<timer> _timer;
|
||||
class Periodic {
|
||||
shared_ptr<Timer> _timer;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor initializes a shared pointer of type timer
|
||||
*/
|
||||
periodic(function<void()> callback, uint64_t time);
|
||||
Periodic(function<void()> callback, uint64_t time);
|
||||
|
||||
/**
|
||||
* Stop periodic
|
||||
@ -108,21 +107,21 @@ class periodic {
|
||||
/**
|
||||
* The destructor stops the periodic
|
||||
*/
|
||||
~periodic();
|
||||
~Periodic();
|
||||
};
|
||||
|
||||
/**
|
||||
* Class delayed for delayed callback execution in ms
|
||||
*/
|
||||
class delayed {
|
||||
shared_ptr<timer> _timer;
|
||||
class Delayed {
|
||||
shared_ptr<Timer> _timer;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor initializes a shared pointer of type timer
|
||||
*/
|
||||
delayed(function<void()> callback, uint64_t time);
|
||||
Delayed(function<void()> callback, uint64_t time);
|
||||
|
||||
/**
|
||||
* Stop delayed
|
||||
@ -147,13 +146,10 @@ class delayed {
|
||||
/**
|
||||
* The destructor stops the delayed
|
||||
*/
|
||||
~delayed();
|
||||
~Delayed();
|
||||
|
||||
};
|
||||
|
||||
shared_ptr<periodic> Periodic(function<void()> callback, uint64_t time);
|
||||
shared_ptr<delayed> Delayed(function<void()> callback, uint64_t time);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,13 @@ using namespace std;
|
||||
#include "engine.hpp"
|
||||
namespace marcelb {
|
||||
namespace asynco {
|
||||
namespace triggers {
|
||||
|
||||
/**
|
||||
* trigger class, for event-driven programming.
|
||||
* Trigger class, for event-driven programming.
|
||||
* These events are typed according to the arguments of the callback function
|
||||
*/
|
||||
template<typename... T>
|
||||
class trigger {
|
||||
class Trigger {
|
||||
private:
|
||||
mutex m_eve;
|
||||
unordered_map<string, vector<function<void(T...)>>> triggers;
|
||||
@ -48,7 +47,7 @@ class trigger {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an trigger listener from an event
|
||||
* Remove an Trigger listener from an event
|
||||
*/
|
||||
void off(const string& key) {
|
||||
lock_guard _off(m_eve);
|
||||
@ -56,7 +55,7 @@ class trigger {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all trigger listener
|
||||
* Remove all Trigger listener
|
||||
*/
|
||||
void off() {
|
||||
lock_guard _off(m_eve);
|
||||
@ -65,7 +64,7 @@ class trigger {
|
||||
|
||||
|
||||
/**
|
||||
* Get num of listeners by an trigger key
|
||||
* Get num of listeners by an Trigger key
|
||||
*/
|
||||
unsigned int listeners(const string& key) {
|
||||
return triggers[key].size();
|
||||
@ -85,7 +84,6 @@ class trigger {
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ int64_t rtime_us() {
|
||||
.count();
|
||||
}
|
||||
|
||||
void timer::init() {
|
||||
void Timer::init() {
|
||||
st.async_wait( [this] (const boost::system::error_code&) {
|
||||
if (!_stop) {
|
||||
callback();
|
||||
@ -27,7 +27,7 @@ void timer::init() {
|
||||
});
|
||||
}
|
||||
|
||||
timer::timer (function<void()> _callback, uint64_t _time, bool _repeate) :
|
||||
Timer::Timer (function<void()> _callback, uint64_t _time, bool _repeate) :
|
||||
st(_asynco_engine.io_context, boost::asio::chrono::milliseconds(_time)),
|
||||
_stop(false),
|
||||
repeate(_repeate),
|
||||
@ -37,109 +37,74 @@ timer::timer (function<void()> _callback, uint64_t _time, bool _repeate) :
|
||||
init();
|
||||
}
|
||||
|
||||
void timer::stop() {
|
||||
void Timer::stop() {
|
||||
_stop = true;
|
||||
st.cancel();
|
||||
}
|
||||
|
||||
void timer::now() {
|
||||
void Timer::now() {
|
||||
st.cancel();
|
||||
}
|
||||
|
||||
uint64_t timer::ticks() {
|
||||
uint64_t Timer::ticks() {
|
||||
return _ticks;
|
||||
}
|
||||
|
||||
bool timer::stoped() {
|
||||
bool Timer::stoped() {
|
||||
return _stop;
|
||||
}
|
||||
|
||||
timer::~timer() {
|
||||
Timer::~Timer() {
|
||||
stop();
|
||||
}
|
||||
|
||||
periodic::periodic(function<void()> callback, uint64_t time) :
|
||||
_timer(make_shared<timer> (callback, time, true)) {
|
||||
Periodic::Periodic(function<void()> callback, uint64_t time) :
|
||||
_timer(make_shared<Timer> (callback, time, true)) {
|
||||
}
|
||||
|
||||
void periodic::stop() {
|
||||
void Periodic::stop() {
|
||||
_timer->stop();
|
||||
}
|
||||
|
||||
void periodic::now() {
|
||||
void Periodic::now() {
|
||||
_timer->now();
|
||||
}
|
||||
|
||||
uint64_t periodic::ticks() {
|
||||
uint64_t Periodic::ticks() {
|
||||
return _timer->ticks();
|
||||
}
|
||||
|
||||
bool periodic::stoped() {
|
||||
bool Periodic::stoped() {
|
||||
return _timer->stoped();
|
||||
}
|
||||
|
||||
periodic::~periodic() {
|
||||
Periodic::~Periodic() {
|
||||
stop();
|
||||
}
|
||||
|
||||
delayed::delayed(function<void()> callback, uint64_t time) :
|
||||
_timer(make_shared<timer> (callback, time, false)) {
|
||||
Delayed::Delayed(function<void()> callback, uint64_t time) :
|
||||
_timer(make_shared<Timer> (callback, time, false)) {
|
||||
}
|
||||
|
||||
void delayed::stop() {
|
||||
void Delayed::stop() {
|
||||
_timer->stop();
|
||||
}
|
||||
|
||||
void delayed::now() {
|
||||
void Delayed::now() {
|
||||
_timer->now();
|
||||
}
|
||||
|
||||
bool delayed::expired() {
|
||||
bool Delayed::expired() {
|
||||
return bool(_timer->ticks());
|
||||
}
|
||||
|
||||
bool delayed::stoped() {
|
||||
bool Delayed::stoped() {
|
||||
return _timer->stoped();
|
||||
}
|
||||
|
||||
delayed::~delayed() {
|
||||
Delayed::~Delayed() {
|
||||
stop();
|
||||
}
|
||||
|
||||
mutex p_io, d_io;
|
||||
vector<shared_ptr<periodic>> periodic_calls_container;
|
||||
vector<shared_ptr<delayed>> delayed_calls_container;
|
||||
|
||||
shared_ptr<periodic> Periodic(function<void()> callback, uint64_t time) {
|
||||
shared_ptr<periodic> periodic_ptr(make_shared<periodic>(callback, time));
|
||||
async_ ( [&, periodic_ptr](){
|
||||
lock_guard<mutex> lock(p_io);
|
||||
periodic_calls_container.push_back(periodic_ptr);
|
||||
for (uint32_t i=0; i<periodic_calls_container.size(); i++) {
|
||||
if (periodic_calls_container[i]->stoped()) {
|
||||
periodic_calls_container.erase(periodic_calls_container.begin()+i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
});
|
||||
return periodic_ptr;
|
||||
}
|
||||
|
||||
shared_ptr<delayed> Delayed(function<void()> callback, uint64_t time) {
|
||||
shared_ptr<delayed> delayed_ptr(make_shared<delayed>(callback, time));
|
||||
async_ ( [&, delayed_ptr](){
|
||||
lock_guard<mutex> lock(p_io);
|
||||
delayed_calls_container.push_back(delayed_ptr);
|
||||
for (uint32_t i=0; i<delayed_calls_container.size(); i++) {
|
||||
if (delayed_calls_container[i]->stoped() || delayed_calls_container[i]->expired()) {
|
||||
delayed_calls_container.erase(delayed_calls_container.begin()+i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
});
|
||||
return delayed_ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
319
test/main.cpp
319
test/main.cpp
@ -7,7 +7,6 @@
|
||||
#include "define.hpp"
|
||||
|
||||
using namespace marcelb::asynco;
|
||||
using namespace triggers;
|
||||
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
@ -18,80 +17,97 @@ using namespace triggers;
|
||||
using namespace std;
|
||||
using namespace this_thread;
|
||||
|
||||
asyncable<int> c2 (int a) {
|
||||
co_return a*2;
|
||||
}
|
||||
|
||||
asyncable<void> sleep_co (int a) {
|
||||
sleep(a);
|
||||
cout << "Gotov" << endl;
|
||||
co_return;
|
||||
}
|
||||
|
||||
|
||||
void sleep_to (int _time) {
|
||||
promise<void> _promise;
|
||||
delayed t( [&]() {
|
||||
_promise.set_value();
|
||||
}, _time);
|
||||
asyncable<void> c () {
|
||||
cout << "Ispisi" << endl;
|
||||
co_await c2(0);
|
||||
co_return;
|
||||
}
|
||||
|
||||
return _promise.get_future().get();
|
||||
}
|
||||
|
||||
void promise_reject (int _time) {
|
||||
promise<void> _promise;
|
||||
delayed t( [&]() {
|
||||
try {
|
||||
// simulate except
|
||||
throw runtime_error("Error simulation");
|
||||
_promise.set_value();
|
||||
} catch (...) {
|
||||
_promise.set_exception(current_exception());
|
||||
}
|
||||
}, _time);
|
||||
|
||||
return _promise.get_future().get();
|
||||
}
|
||||
// void sleep_to (int _time) {
|
||||
// promise<void> _promise;
|
||||
// Delayed t( [&]() {
|
||||
// _promise.set_value();
|
||||
// }, _time);
|
||||
|
||||
void notLambdaFunction() {
|
||||
cout << "Call to not lambda function" << endl;
|
||||
}
|
||||
// return _promise.get_future().get();
|
||||
// }
|
||||
|
||||
class clm {
|
||||
public:
|
||||
void classMethode() {
|
||||
cout << "Call class method" << endl;
|
||||
}
|
||||
};
|
||||
// void promise_reject (int _time) {
|
||||
// promise<void> _promise;
|
||||
// Delayed t( [&]() {
|
||||
// try {
|
||||
// // simulate except
|
||||
// throw runtime_error("Error simulation");
|
||||
// _promise.set_value();
|
||||
// } catch (...) {
|
||||
// _promise.set_exception(current_exception());
|
||||
// }
|
||||
// }, _time);
|
||||
|
||||
// ------------------ EXTEND OWN CLASS WITH EVENTS -------------------
|
||||
// return _promise.get_future().get();
|
||||
// }
|
||||
|
||||
class myOwnClass : public trigger<int> {
|
||||
public:
|
||||
myOwnClass() : trigger() {};
|
||||
};
|
||||
// void notLambdaFunction() {
|
||||
// cout << "Call to not lambda function" << endl;
|
||||
// }
|
||||
|
||||
// class clm {
|
||||
// public:
|
||||
// void classMethode() {
|
||||
// cout << "Call class method" << endl;
|
||||
// }
|
||||
// };
|
||||
|
||||
// // ------------------ EXTEND OWN CLASS WITH EVENTS -------------------
|
||||
|
||||
// class myOwnClass : public Trigger<int> {
|
||||
// public:
|
||||
// myOwnClass() : Trigger() {};
|
||||
// };
|
||||
|
||||
// ----------------- MULTIPLE TRIGGERS IN ONE CLASS ------------------
|
||||
|
||||
class ClassWithTriggers {
|
||||
trigger<int> emitter1;
|
||||
trigger<string> emitter2;
|
||||
// class ClassWithTriggers {
|
||||
// Trigger<int> emitter1;
|
||||
// Trigger<string> emitter2;
|
||||
|
||||
public:
|
||||
template<typename... T>
|
||||
void on(const string& key, function<void(T...)> callback) {
|
||||
if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, int>) {
|
||||
emitter1.on(key, callback);
|
||||
}
|
||||
else if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, string>) {
|
||||
emitter2.on(key, callback);
|
||||
}
|
||||
}
|
||||
// public:
|
||||
// template<typename... T>
|
||||
// void on(const string& key, function<void(T...)> callback) {
|
||||
// if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, int>) {
|
||||
// emitter1.on(key, callback);
|
||||
// }
|
||||
// else if constexpr (sizeof...(T) == 1 && is_same_v<tuple_element_t<0, tuple<T...>>, string>) {
|
||||
// emitter2.on(key, callback);
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename... Args>
|
||||
void tick(const string& key, Args&&... args) {
|
||||
if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, int>) {
|
||||
emitter1.tick(key, forward<Args>(args)...);
|
||||
}
|
||||
else if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, string>) {
|
||||
emitter2.tick(key, forward<Args>(args)...);
|
||||
}
|
||||
else {
|
||||
static_assert(sizeof...(Args) == 0, "Unsupported number or types of arguments");
|
||||
}
|
||||
}
|
||||
};
|
||||
// template <typename... Args>
|
||||
// void tick(const string& key, Args&&... args) {
|
||||
// if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, int>) {
|
||||
// emitter1.tick(key, forward<Args>(args)...);
|
||||
// }
|
||||
// else if constexpr (sizeof...(Args) == 1 && is_same_v<tuple_element_t<0, tuple<Args...>>, string>) {
|
||||
// emitter2.tick(key, forward<Args>(args)...);
|
||||
// }
|
||||
// else {
|
||||
// static_assert(sizeof...(Args) == 0, "Unsupported number or types of arguments");
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
int main () {
|
||||
@ -101,36 +117,36 @@ int main () {
|
||||
// --------------- TIME ASYNCHRONOUS FUNCTIONS --------------
|
||||
|
||||
/**
|
||||
* Init periodic and delayed; clear periodic and delayed
|
||||
* Init Periodic and delayed; clear Periodic and delayed
|
||||
*/
|
||||
|
||||
// periodic inter1 ([&]() {
|
||||
// cout << "periodic prvi " << rtime_ms() - start << endl;
|
||||
// Periodic inter1 ([&]() {
|
||||
// cout << "Periodic prvi " << rtime_ms() - start << endl;
|
||||
// }, 1000);
|
||||
|
||||
// periodic inter2 ([&]() {
|
||||
// cout << "periodic drugi " << rtime_ms() - start << endl;
|
||||
// Periodic inter2 ([&]() {
|
||||
// cout << "Periodic drugi " << rtime_ms() - start << endl;
|
||||
// }, 2000);
|
||||
|
||||
// periodic inter3 ([&]() {
|
||||
// cout << "periodic treći " << rtime_ms() - start << endl;
|
||||
// Periodic inter3 ([&]() {
|
||||
// cout << "Periodic treći " << rtime_ms() - start << endl;
|
||||
// }, 1000);
|
||||
|
||||
// periodic inter4 ([&]() {
|
||||
// // cout << "periodic cetvrti " << rtime_ms() - start << endl;
|
||||
// Periodic inter4 ([&]() {
|
||||
// // cout << "Periodic cetvrti " << rtime_ms() - start << endl;
|
||||
// cout << "Ticks " << inter3.ticks() << endl;
|
||||
// }, 500);
|
||||
|
||||
// periodic inter5 ([&]() {
|
||||
// cout << "periodic peti " << rtime_ms() - start << endl;
|
||||
// Periodic inter5 ([&]() {
|
||||
// cout << "Periodic peti " << rtime_ms() - start << endl;
|
||||
// }, 2000);
|
||||
|
||||
// periodic inter6 ([&]() {
|
||||
// cout << "periodic sesti " << rtime_ms() - start << endl;
|
||||
// Periodic inter6 ([&]() {
|
||||
// cout << "Periodic sesti " << rtime_ms() - start << endl;
|
||||
// }, 3000);
|
||||
|
||||
// delayed time1 ( [&] () {
|
||||
// cout << "Close periodic 1 i 2 " << rtime_ms() - start << endl;
|
||||
// Delayed time1 ( [&] () {
|
||||
// cout << "Close Periodic 1 i 2 " << rtime_ms() - start << endl;
|
||||
// inter1.stop();
|
||||
// cout << "inter1.stop " << endl;
|
||||
// inter2.stop();
|
||||
@ -138,8 +154,8 @@ int main () {
|
||||
// }, 8000);
|
||||
|
||||
|
||||
// delayed time2 ([&] () {
|
||||
// cout << "Close periodic 3 " << rtime_ms() - start << endl;
|
||||
// Delayed time2 ([&] () {
|
||||
// cout << "Close Periodic 3 " << rtime_ms() - start << endl;
|
||||
// inter3.stop();
|
||||
// cout << "Stoped " << inter3.stoped() << endl;
|
||||
// // time1.stop();
|
||||
@ -244,7 +260,7 @@ int main () {
|
||||
// })) << endl;
|
||||
|
||||
// /**
|
||||
// * Sleep with delayed sleep implement
|
||||
// * Sleep with Delayed sleep implement
|
||||
// */
|
||||
|
||||
// sleep_to(3000);
|
||||
@ -335,9 +351,9 @@ int main () {
|
||||
// * initialization of typed events
|
||||
// */
|
||||
|
||||
// trigger<int, int> ev2int;
|
||||
// trigger<int, string> evintString;
|
||||
// trigger<> evoid;
|
||||
// Trigger<int, int> ev2int;
|
||||
// Trigger<int, string> evintString;
|
||||
// Trigger<> evoid;
|
||||
|
||||
// ev2int.on("sum", [](int a, int b) {
|
||||
// cout << "Sum " << a+b << endl;
|
||||
@ -390,7 +406,7 @@ int main () {
|
||||
|
||||
// myOwnClass myclass;
|
||||
|
||||
// delayed t( [&] {
|
||||
// Delayed t( [&] {
|
||||
// myclass.tick("constructed", 1);
|
||||
// }, 200);
|
||||
|
||||
@ -404,18 +420,18 @@ int main () {
|
||||
// *
|
||||
// */
|
||||
|
||||
ClassWithTriggers mt;
|
||||
// ClassWithTriggers mt;
|
||||
|
||||
mt.on<int>("int", function<void(int)>([&](int i) {
|
||||
cout << "Emit int " << i << endl;
|
||||
}));
|
||||
// mt.on<int>("int", function<void(int)>([&](int i) {
|
||||
// cout << "Emit int " << i << endl;
|
||||
// }));
|
||||
|
||||
mt.on<string>("string", function<void(string)>([&](string s) {
|
||||
cout << "Emit string " << s << endl;
|
||||
}));
|
||||
// mt.on<string>("string", function<void(string)>([&](string s) {
|
||||
// cout << "Emit string " << s << endl;
|
||||
// }));
|
||||
|
||||
mt.tick("int", 5);
|
||||
mt.tick("string", string("Hello world"));
|
||||
// mt.tick("int", 5);
|
||||
// mt.tick("string", string("Hello world"));
|
||||
|
||||
|
||||
// auto status = fs::read("test1.txt");
|
||||
@ -446,9 +462,124 @@ int main () {
|
||||
|
||||
// // ----------------------------------------------------------------------------------------------------
|
||||
|
||||
cout << "Run" << endl;
|
||||
_asynco_engine.run();
|
||||
|
||||
// auto i = async_ ( []() -> asyncable<int> {
|
||||
// cout << "aaaa" << endl;
|
||||
// co_return 5;
|
||||
// });
|
||||
|
||||
// auto i = async_ (retint());
|
||||
|
||||
// auto i_ = await_(i);
|
||||
|
||||
// cout << i_ << endl;
|
||||
|
||||
|
||||
// Periodic a( []() -> asyncable<void> {
|
||||
// cout << "corutina" << endl;
|
||||
// // co_await retint();
|
||||
// }, 2000);
|
||||
|
||||
|
||||
// Periodic b( []() {
|
||||
// cout << "funckija" << endl;
|
||||
// }, 2000);
|
||||
|
||||
|
||||
// Trigger<int, int> ev2int;
|
||||
// Trigger<int, string> evintString;
|
||||
// Trigger<> evoid;
|
||||
|
||||
// ev2int.on("sum", [](int a, int b) -> asyncable<void> {
|
||||
// cout << "Sum " << a+b << endl;
|
||||
// });
|
||||
|
||||
// ev2int.on("sum", [](int a, int b) -> asyncable<void> {
|
||||
// cout << "Sum done" << endl;
|
||||
// });
|
||||
|
||||
// evintString.on("substract", [](int a, string b) -> asyncable<void> {
|
||||
// cout << "Substract " << a-stoi(b) << endl;
|
||||
// });
|
||||
|
||||
// evoid.on("void", []() {
|
||||
// auto a = await_ (async_ (c2(34)));
|
||||
// cout << "A " << a << endl;
|
||||
// });
|
||||
|
||||
|
||||
// auto c1 = []() -> asyncable<void> {
|
||||
// cout << "Roge " << endl;
|
||||
// co_return;
|
||||
|
||||
// };
|
||||
|
||||
// auto a = await_ ( c2(3));
|
||||
// cout << a << endl;
|
||||
|
||||
|
||||
// await_ ([]() -> asyncable<void> {
|
||||
// cout << "Hello" << endl;
|
||||
// co_await c2(4);
|
||||
// co_return;
|
||||
// }());
|
||||
|
||||
async_ ([]() -> asyncable<void> {
|
||||
cout << "1" << endl;
|
||||
co_await sleep_co(1);
|
||||
co_return;
|
||||
}());
|
||||
|
||||
async_ ([]() -> asyncable<void> {
|
||||
cout << "2" << endl;
|
||||
co_await sleep_co(1);
|
||||
co_return;
|
||||
}());
|
||||
|
||||
async_ ([]() -> asyncable<void> {
|
||||
cout << "3" << endl;
|
||||
co_await sleep_co(1);
|
||||
co_return;
|
||||
}());
|
||||
|
||||
async_ ([]() -> asyncable<void> {
|
||||
cout << "4" << endl;
|
||||
co_await sleep_co(1);
|
||||
co_return;
|
||||
}());
|
||||
|
||||
async_ ([]() -> asyncable<void> {
|
||||
cout << "5" << endl;
|
||||
co_await sleep_co(1);
|
||||
co_return;
|
||||
}());
|
||||
|
||||
|
||||
// await_ ([]() {
|
||||
// cout << "Hello" << endl;
|
||||
// });
|
||||
|
||||
// Periodic p( []() {
|
||||
// async_ (
|
||||
// c2(34)
|
||||
// );
|
||||
// }, 2000);
|
||||
|
||||
// await_( async_co2 ( [c1 = move(c1)]() -> asyncable<void> {
|
||||
// cout << "Baba roga" << endl;
|
||||
// co_await c1();
|
||||
// }));
|
||||
|
||||
// string emited2 = "2";
|
||||
|
||||
// evoid.on("void", [&]() -> asyncable<void> {
|
||||
// cout << "Void emited " << emited2 << endl;
|
||||
// });
|
||||
|
||||
// evoid.tick("void");
|
||||
|
||||
cout << "-------------end main-------------" << endl;
|
||||
_asynco_engine.run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user