2019-12-03 19:23:33 +00:00
|
|
|
//
|
|
|
|
// Created by loki on 6/10/19.
|
|
|
|
//
|
|
|
|
|
2019-12-11 18:06:52 +00:00
|
|
|
#ifndef SUNSHINE_THREAD_SAFE_H
|
|
|
|
#define SUNSHINE_THREAD_SAFE_H
|
2019-12-03 19:23:33 +00:00
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <mutex>
|
|
|
|
#include <condition_variable>
|
|
|
|
|
|
|
|
#include "utility.h"
|
|
|
|
|
|
|
|
namespace safe {
|
2019-12-11 18:06:52 +00:00
|
|
|
template<class T>
|
|
|
|
class event_t {
|
|
|
|
using status_t = util::either_t<
|
|
|
|
(std::is_same_v<T, bool> ||
|
|
|
|
util::instantiation_of_v<std::unique_ptr, T> ||
|
|
|
|
util::instantiation_of_v<std::shared_ptr, T> ||
|
|
|
|
std::is_pointer_v<T>),
|
|
|
|
T, std::optional<T>>;
|
|
|
|
|
|
|
|
public:
|
|
|
|
template<class...Args>
|
|
|
|
void raise(Args &&...args) {
|
|
|
|
std::lock_guard lg { _lock };
|
|
|
|
if(!_continue) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_status = status_t { std::forward<Args>(args)... };
|
|
|
|
|
|
|
|
_cv.notify_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t pop() {
|
|
|
|
std::unique_lock ul{_lock};
|
|
|
|
|
|
|
|
if (!_continue) {
|
|
|
|
return util::false_v<status_t>;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!_status) {
|
|
|
|
_cv.wait(ul);
|
|
|
|
|
|
|
|
if (!_continue) {
|
|
|
|
return util::false_v<status_t>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto val = std::move(_status);
|
|
|
|
_status = util::false_v<status_t>;
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool peek() {
|
|
|
|
std::lock_guard lg { _lock };
|
|
|
|
|
|
|
|
return (bool)_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
void stop() {
|
|
|
|
std::lock_guard lg{_lock};
|
|
|
|
|
|
|
|
_continue = false;
|
|
|
|
|
|
|
|
_cv.notify_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool running() const {
|
|
|
|
return _continue;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
|
|
|
|
bool _continue{true};
|
|
|
|
status_t _status;
|
|
|
|
|
|
|
|
std::condition_variable _cv;
|
|
|
|
std::mutex _lock;
|
|
|
|
};
|
2019-12-03 19:23:33 +00:00
|
|
|
|
|
|
|
template<class T>
|
|
|
|
class queue_t {
|
|
|
|
using status_t = util::either_t<
|
|
|
|
(std::is_same_v<T, bool> ||
|
|
|
|
util::instantiation_of_v<std::unique_ptr, T> ||
|
|
|
|
util::instantiation_of_v<std::shared_ptr, T> ||
|
|
|
|
std::is_pointer_v<T>),
|
|
|
|
T, std::optional<T>>;
|
|
|
|
|
|
|
|
public:
|
|
|
|
template<class ...Args>
|
2019-12-11 18:06:52 +00:00
|
|
|
void raise(Args &&... args) {
|
2019-12-03 19:23:33 +00:00
|
|
|
std::lock_guard lg{_lock};
|
|
|
|
|
|
|
|
if(!_continue) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_queue.emplace_back(std::forward<Args>(args)...);
|
|
|
|
|
|
|
|
_cv.notify_all();
|
|
|
|
}
|
|
|
|
|
2019-12-08 20:16:02 +00:00
|
|
|
bool peek() {
|
|
|
|
std::lock_guard lg { _lock };
|
|
|
|
|
|
|
|
return !_queue.empty();
|
|
|
|
}
|
|
|
|
|
2019-12-03 19:23:33 +00:00
|
|
|
status_t pop() {
|
|
|
|
std::unique_lock ul{_lock};
|
|
|
|
|
|
|
|
if (!_continue) {
|
|
|
|
return util::false_v<status_t>;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (_queue.empty()) {
|
|
|
|
_cv.wait(ul);
|
|
|
|
|
|
|
|
if (!_continue) {
|
|
|
|
return util::false_v<status_t>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto val = std::move(_queue.front());
|
|
|
|
_queue.erase(std::begin(_queue));
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<T> &unsafe() {
|
|
|
|
return _queue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void stop() {
|
|
|
|
std::lock_guard lg{_lock};
|
|
|
|
|
|
|
|
_continue = false;
|
|
|
|
|
|
|
|
_cv.notify_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool running() const {
|
|
|
|
return _continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
bool _continue{true};
|
|
|
|
|
|
|
|
std::mutex _lock;
|
|
|
|
std::condition_variable _cv;
|
|
|
|
std::vector<T> _queue;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-12-11 18:06:52 +00:00
|
|
|
#endif //SUNSHINE_THREAD_SAFE_H
|