| | |
| | | * ===================================================================================== |
| | | */ |
| | | #include "robust.h" |
| | | #include <chrono> |
| | | #include <thread> |
| | | |
| | | using namespace std::chrono; |
| | | using namespace std::chrono_literals; |
| | | |
| | | namespace |
| | | { |
| | | void yield() { std::this_thread::sleep_for(10us); } |
| | | } // namespace |
| | | |
| | | namespace robust |
| | | { |
| | | |
| | | namespace |
| | | bool AtomicReqRep::ClientRequest(const Data request, Data &reply) |
| | | { |
| | | static_assert(sizeof(steady_clock::duration) == sizeof(int64_t)); |
| | | |
| | | auto Now() { return steady_clock::now().time_since_epoch(); } |
| | | void Yield() { std::this_thread::sleep_for(10us); } |
| | | |
| | | } // namespace |
| | | |
| | | void QuickSleep() { Yield(); } |
| | | |
| | | bool FMutex::try_lock() |
| | | { |
| | | if (flock(fd_, LOCK_EX | LOCK_NB) == 0) { |
| | | if (mtx_.try_lock()) { |
| | | return true; |
| | | } else { |
| | | flock(fd_, LOCK_UN); |
| | | auto end_time = now() + 3s; |
| | | do { |
| | | Data cur = data_.load(); |
| | | if (GetState(cur) == eStateFree && |
| | | DataCas(cur, Encode(request, eStateRequest))) { |
| | | do { |
| | | yield(); |
| | | cur = data_.load(); |
| | | if (GetState(cur) == eStateReply) { |
| | | DataCas(cur, Encode(0, eStateFree)); |
| | | reply = Decode(cur); |
| | | return true; |
| | | } |
| | | } while (now() < end_time); |
| | | } |
| | | } |
| | | yield(); |
| | | } while (now() < end_time); |
| | | return false; |
| | | } |
| | | void FMutex::lock() |
| | | |
| | | bool AtomicReqRep::ServerProcess(Handler onReq) |
| | | { |
| | | //Note: the lock order affects performance a lot, |
| | | // locking fd_ first is about 100 times faster than locking mtx_ first. |
| | | flock(fd_, LOCK_EX); |
| | | mtx_.lock(); |
| | | } |
| | | void FMutex::unlock() |
| | | { |
| | | mtx_.unlock(); |
| | | flock(fd_, LOCK_UN); |
| | | Data cur = data_.load(); |
| | | switch (GetState(cur)) { |
| | | case eStateRequest: |
| | | if (DataCas(cur, Encode(onReq(Decode(cur)), eStateReply))) { |
| | | timestamp_ = now(); |
| | | return true; |
| | | } |
| | | break; |
| | | case eStateReply: |
| | | if (timestamp_.load() + 3s < now()) { |
| | | DataCas(cur, Encode(0, eStateFree)); |
| | | } |
| | | break; |
| | | case eStateFree: |
| | | default: break; |
| | | } |
| | | return false; |
| | | } |
| | | } // namespace robust |