File lock.h
File List > device > util > lock.h
Go to the documentation of this file
#pragma once
#include <atomic>
#include <optional>
#include "timeout.h"
namespace jac {
class TimeoutLock {
Timeout _timeout;
bool _locked = false;
int _owner = 0;
std::mutex _mutex;
int _stops = 0;
std::function<void()> _callback;
public:
TimeoutLock(std::chrono::milliseconds duration, std::function<void()> callback):
_timeout(duration),
_callback(callback)
{}
TimeoutLock(const TimeoutLock&) = delete;
TimeoutLock(TimeoutLock&&) = delete;
TimeoutLock& operator=(const TimeoutLock&) = delete;
TimeoutLock& operator=(TimeoutLock&&) = delete;
void init() {
_timeout.init();
}
bool lock(int who) {
std::scoped_lock<std::mutex> _(_mutex);
if (_locked && _owner == who) {
throw std::runtime_error("Lock already locked, reset() should be used to reset the timeout");
}
if (!_locked) {
_locked = true;
_owner = who;
_timeout.start([this]() {
std::scoped_lock<std::mutex> __(_mutex);
if (_callback) {
_callback();
}
_locked = false;
});
return true;
}
return false;
}
void resetTimeout(int who) {
std::scoped_lock<std::mutex> _(_mutex);
if (!_locked || _owner != who) {
return;
}
_stops = _stops > 0 ? _stops - 1 : 0;
if (_stops == 0) {
_timeout.reset();
}
}
void stopTimeout(int who) {
std::scoped_lock<std::mutex> _(_mutex);
if (!_locked || _owner != who) {
return;
}
_timeout.stop();
_stops++;
}
bool unlock(int who) {
std::scoped_lock<std::mutex> _(_mutex);
if (_owner != who) {
return false;
}
_timeout.stop();
_locked = false;
return true;
}
void forceUnlock() {
std::scoped_lock<std::mutex> _(_mutex);
_timeout.stop();
_locked = false;
}
bool ownedBy(int who) {
std::scoped_lock<std::mutex> _(_mutex);
return _locked && _owner == who;
}
~TimeoutLock() {
_timeout.stop();
}
};
} // namespace jac