Skip to content

Instantly share code, notes, and snippets.

@tobq
Last active February 21, 2021 04:22
Show Gist options
  • Save tobq/5e2ba637936b2c0f734fbd4dfe7870fc to your computer and use it in GitHub Desktop.
Save tobq/5e2ba637936b2c0f734fbd4dfe7870fc to your computer and use it in GitHub Desktop.
#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