Created
October 3, 2024 22:27
-
-
Save skeeto/42adc0c90a156d4457422e034be697e8 to your computer and use it in GitHub Desktop.
Slim Reader/Writer Condition Variable Demo / Test
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
// 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