Skip to content

Instantly share code, notes, and snippets.

@jweinst1
Last active May 19, 2026 09:05
Show Gist options
  • Select an option

  • Save jweinst1/e02c7bed2009b007678ffa7ac326f4e6 to your computer and use it in GitHub Desktop.

Select an option

Save jweinst1/e02c7bed2009b007678ffa7ac326f4e6 to your computer and use it in GitHub Desktop.
implementation of an atomic shared pointer
## Summary
This is an atomic shared pointer implementation with a flow test that supports reseting, copying, assignment, and compare and exchanging.
#include <atomic>
#include <thread>
#include <chrono>
#include <cstdio>
#include <assert.h>
static bool KEEP_GOING = true;
template<class T>
class AtomicPointer {
public:
AtomicPointer(): _ptr(nullptr), _counter(nullptr)
{}
AtomicPointer(T* ptr): _ptr(ptr),
_counter(new std::atomic<size_t>(1))
{}
bool valid() const { return _ptr.laod() == nullptr; }
AtomicPointer(const AtomicPointer<T>& other) {
_counter.store(other._counter.load());
_counter.load()->fetch_add(1);
_ptr.store(other._ptr.load());
}
AtomicPointer<T>& operator=(const AtomicPointer<T>& other) noexcept
{
if (this != &other) {
size_t checker = 0;
if (_counter.load() != nullptr && (checker = _counter.load()->fetch_sub(1)) == 1) {
printf("= DELETING: %p\n", _ptr.load());
assert(checker-1 == 0);
delete _ptr.load();
delete _counter.load();
}
_counter.store(other._counter.load());
_counter.load()->fetch_add(1);
_ptr.store(other._ptr.load());
}
return *this;
}
T* operator->() const { return _ptr.load(); }
inline T* get() const { return _ptr.load(); }
void reset(T* ptr = nullptr) {
size_t checker = 0;
if ((checker = _counter.load()->fetch_sub(1)) == 1) {
printf("RESET DELETING: %p\n", _ptr.load());
assert(checker-1 == 0);
delete _ptr.load();
delete _counter.load();
}
_ptr.store(ptr);
_counter.store(new std::atomic<size_t>(1));
}
bool cmp_exchange(T* expected, T* desired = nullptr) {
if (_ptr.compare_exchange_strong(expected, desired)) {
size_t checker = 0;
if ((checker = _counter.load()->fetch_sub(1)) == 1) {
printf("EXCHANGE DELETING: %p\n", expected);
assert(checker-1 == 0);
delete expected;
delete _counter.load();
}
_counter.store(new std::atomic<size_t>(1));
return true;
}
return false;
}
~AtomicPointer() {
size_t checker = 0;
if ((checker = _counter.load()->fetch_sub(1)) == 1) {
printf("DELETING: %p\n", _ptr.load());
assert(checker-1 == 0);
delete _ptr.load();
assert(checker-1 == 0);
_ptr.store(nullptr);
delete _counter.load();
}
}
private:
std::atomic<T*> _ptr;
std::atomic<std::atomic<size_t>*> _counter;
};
class Sample {
public:
Sample(): _a(0), _b(0) {}
void set(long a = 0, long b = 0) {
_a = a;
_b = b;
}
long sum() const { return _a + _b; }
private:
long _a;
long _b;
};
#define THREAD_COUNT 10
static void doWork(AtomicPointer<Sample> ptr, int times) {
size_t i = 0;
AtomicPointer<Sample> cptr(new Sample());
printf("Starting do work\n");
if (times != 0) {
std::thread(doWork, ptr, times - 1).detach();
}
while (KEEP_GOING) {
ptr->set(1, 3);
long d = ptr->sum();
ptr.reset(new Sample());
Sample* nptr = new Sample();
//AtomicPointer<Sample> foo2(ptr);
ptr.cmp_exchange(ptr.get(), nptr);
if (i % 3 == 0) {
ptr = cptr;
}
++i;
}
}
int main(int argc, char const *argv[])
{
std::puts("Atomic Ref Count");
Sample* sptr = new Sample();
AtomicPointer<Sample> aptr(sptr);
std::thread threadList[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; ++i)
{
printf("Starting a new thread\n");
threadList[i] = std::thread(doWork, aptr, 5);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
KEEP_GOING = false;
for (int i = 0; i < THREAD_COUNT; ++i)
{
threadList[i].join();
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment