Last active
February 21, 2021 04:22
-
-
Save tobq/5e2ba637936b2c0f734fbd4dfe7870fc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<atomic> | |
template<class T = uint64_t> requires std::integral<T> | |
class read_write_semaphore { | |
std::atomic<T> reading; | |
T max = std::numeric_limits<T>::max(); | |
bool writer_acquire() { | |
auto expected = reading.load(); | |
T desired; | |
desired = max; | |
return reading.compare_exchange_weak(expected, desired); | |
} | |
bool reader_acquire() { | |
auto expected = reading.load(); | |
T desired; | |
do { | |
desired = expected + 1; | |
} while (!reading.compare_exchange_weak(expected, desired)); | |
} | |
void reader_release() { | |
auto expected = reading.load(); | |
T desired; | |
do { | |
desired = expected - 1; | |
} while (!reading.compare_exchange_weak(expected, desired)); | |
} | |
void writer_release() { | |
reading = 0; | |
} | |
public: | |
class lock_free_read_token { | |
read_write_semaphore sem; | |
public: | |
explicit lock_free_read_token(read_write_semaphore<T> &sem) : sem(sem) { | |
sem.reader_acquire(); | |
} | |
~lock_free_read_token() { | |
sem.reader_release(); | |
} | |
}; | |
class sem_acquire_failure : std::runtime_error { | |
}; | |
class lock_free_write_token { | |
read_write_semaphore sem; | |
public: | |
explicit lock_free_write_token(read_write_semaphore<T> &sem) : sem(sem) { | |
if (!sem.writer_acquire()) throw sem_acquire_failure(); | |
} | |
~lock_free_write_token() { | |
sem.writer_release(); | |
} | |
}; | |
}; | |
template<class T> | |
class lock_free_synced_object { | |
const object &object; | |
lock_free_synced_object(const object &message) : object(message) {} | |
using sem_t = read_write_semaphore<>; | |
bool try_set(T) { | |
try { | |
sem_t::lock_free_write_token l; | |
object.write(); | |
return true; | |
} catch (const sem_t::sem_acquire_failure &) { | |
return false; | |
} | |
} | |
T read() { | |
sem_t::lock_free_read_token l; | |
return object.read(); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment