Skip to content

Instantly share code, notes, and snippets.

@skeeto
Created October 3, 2024 22:27
Show Gist options
  • Save skeeto/42adc0c90a156d4457422e034be697e8 to your computer and use it in GitHub Desktop.
Save skeeto/42adc0c90a156d4457422e034be697e8 to your computer and use it in GitHub Desktop.
Slim Reader/Writer Condition Variable Demo / Test
// Slim Reader/Writer Condition Variable Demo / Test
// $ cc -nostartfiles -o main.exe demo.cpp
// $ cl /GS- demo.cpp /link /subsystem:console kernel32.lib
// This is free and unencumbered software released into the public domain.
#define assert(c) while (!(c)) *(volatile i32 *)-4 = 0
using b32 = signed;
using i32 = signed;
using uz = decltype(sizeof(0));
enum Handle : uz;
enum Lock : uz;
enum Cond : uz;
#define W32(r, p) extern "C" __declspec(dllimport) r __stdcall p noexcept
W32(void, AcquireSRWLockExclusive(Lock *));
W32(void, AcquireSRWLockShared(Lock *));
W32(void, CloseHandle(Handle));
W32(Handle, CreateThread(uz, uz, i32(__stdcall *)(void *), void *, i32, uz));
W32(void, ExitProcess(i32));
W32(void, ReleaseSRWLockExclusive(Lock *));
W32(void, ReleaseSRWLockShared(Lock *));
W32(b32, SleepConditionVariableSRW(Cond *, Lock *, i32, b32));
W32(void, WakeAllConditionVariable(Cond *));
W32(void, WakeConditionVariable(Cond *));
struct Guard {
Lock *l;
Guard(Lock *l) : l{l} { AcquireSRWLockExclusive(l); }
~Guard() { ReleaseSRWLockExclusive(l); }
};
struct RGuard {
Lock *l;
RGuard(Lock *l) : l{l} { AcquireSRWLockShared(l); }
~RGuard() { ReleaseSRWLockShared(l); }
};
static b32 wait(Cond *c, Guard *g, i32 ms = -1)
{
return SleepConditionVariableSRW(c, g->l, ms, 0);
}
static b32 wait(Cond *c, RGuard *g, i32 ms = -1)
{
return SleepConditionVariableSRW(c, g->l, ms, 1);
}
static void signal(Cond *c)
{
WakeConditionVariable(c);
}
static void broadcast(Cond *c)
{
WakeAllConditionVariable(c);
}
struct Test {
Lock lock;
Cond done;
Cond init;
i32 count;
b32 ready;
i32 threads;
i32 value;
};
static i32 __stdcall worker(void *arg)
{
Test *t = (Test *)arg;
for (RGuard g(&t->lock); !t->ready;) {
wait(&t->init, &g);
}
for (i32 i = 0, count = t->count; i < count; i++) {
Guard g(&t->lock);
t->value++;
}
if (Guard g(&t->lock); !--t->threads) {
signal(&t->done);
}
return 0;
}
extern "C" void __stdcall mainCRTStartup(void *)
{
enum {
N = 32,
C = 100000,
};
Test t = {};
t.count = C;
t.threads = N;
for (i32 i = 0; i < N; i++) {
Handle h = CreateThread(0, 0, worker, &t, 0, 0);
assert(h);
CloseHandle(h);
}
Guard g(&t.lock);
t.ready = 1;
broadcast(&t.init);
while (t.threads) {
wait(&t.done, &g);
}
assert(t.value == C*N);
ExitProcess(0);
[[assume(false)]];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment