Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
14_mutex.c
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <lxsameer@lxsameer.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19// Example 14 -- a fiber mutex guarding shared state across workers.
20//
21// Example 05 shared a single atomic counter, the one kind of cross worker state
22// that needs no lock. Most shared state is not a lone atomic. When a fiber has
23// to read a value, act on it, and write the result back as one indivisible
24// step, an atomic increment is not enough and the fibers need mutual exclusion.
25//
26// `srn_fiber_mutex_t` provides it. Unlike an OS mutex it suspends the calling
27// fiber while the lock is held elsewhere and lets the worker run other fibers
28// meanwhile, so it must only ever be called from inside a running fiber. Here
29// many fibers spread across several workers each take the lock, run a small
30// read,modify,write on a plain nonatomic counter, then release. The lock
31// serialises the critical section, so no update is lost and the final total is
32// exact even though the counter itself is not atomic.
33
34#include <stdio.h>
35
37#include <serene/runtime.h>
38
39#define FIBER_COUNT 64
40#define ITERATIONS 100
41#define WORKER_COUNT 4
42
44
45// Plain, nonatomic shared state. It is safe only because every access happens inside the critical
46// section below.
47static long counter;
48
49static srn_fiber_result_t bump(srn_context_t *ctx, void *arg) {
50 (void)ctx;
51 (void)arg;
52 for (int i = 0; i < ITERATIONS; i++) {
54 // The read and the write must not interleave with another fiber. Two fibers
55 // reading the same value would each write it back once and lose an update.
56 long seen = counter;
57 counter = seen + 1;
59 }
60 return nullptr;
61}
62
63int main(void) {
64 SERENE_RUNTIME_INIT_WITH_SCHED(engine, sched, nullptr);
65 srn_context_t *ctx = srn_context_make(engine);
66
68 counter = 0;
69
70 for (int i = 0; i < FIBER_COUNT; i++) {
71 (void)srn_fiber_spawn(ctx, bump, nullptr);
72 }
73
74 long expected = (long)FIBER_COUNT * ITERATIONS;
75 printf(
76 "running %d fibers x %d iterations across %d workers\n", FIBER_COUNT, ITERATIONS, WORKER_COUNT
77 );
79
80 printf(
81 "counted %ld (expected %ld): %s\n", counter, expected,
82 counter == expected ? "every increment landed" : "lost an update"
83 );
84
87 return 0;
88}
#define FIBER_COUNT
Definition 05_parallel.c:37
#define WORKER_COUNT
Definition 05_parallel.c:38
static atomic_uint counter
static srn_fiber_result_t bump(srn_context_t *ctx, void *arg)
Definition 14_mutex.c:49
static srn_fiber_mutex_t lock
Definition 14_mutex.c:43
int main(void)
Definition 14_mutex.c:63
#define ITERATIONS
Definition 14_mutex.c:40
srn_context_t * srn_context_make(srn_engine_t *engine)
Make an empty context, by allocating a new memory block.
Definition context.c:39
int srn_context_release(srn_context_t *ctx)
Definition context.c:64
srn_fiber_t * srn_fiber_spawn(srn_context_t *ctx, srn_fiber_entry_t entry, void *arg)
Make and schedule a fiber with every default, the engine's scheduler, the configured stack size,...
Definition fiber.c:250
void * srn_fiber_result_t
What a fiber's entry produces, type-erased.
Definition fiber.h:161
void srn_fiber_mutex_init(srn_fiber_mutex_t *m)
Initialise m to the unlocked state.
Definition mutex.c:76
void srn_fiber_mutex_unlock(srn_fiber_mutex_t *m)
Release m.
Definition mutex.c:99
void srn_fiber_mutex_lock(srn_fiber_mutex_t *m)
Acquire m.
Definition mutex.c:81
A fiber blocking mutex.
#define SERENE_RUNTIME_SHUTDOWN(engine)
Tear down what SERENE_RUNTIME_INIT brought up, in reverse order, the engine (reactor,...
Definition runtime.h:58
#define SERENE_RUNTIME_INIT_WITH_SCHED(engine, sched, config)
SERENE_RUNTIME_INIT plus a sched variable bound to the engine's scheduler, which every run and fiber ...
Definition runtime.h:46
void srn_sched_run(srn_scheduler_t *sched, size_t nworkers)
Run the scheduler with nworkers os threads draining it, returning once the pool goes quiescent (every...
Definition scheduler.c:875