How to Use Atomic Types in C
This article will demonstrate multiple methods about how to use atomic types in C.
Use Atomic Types to Synchronize Accesses to Shared Resources Implicitly
Atomic-type objects are the only ones that can be accessed and modified by multiple threads concurrently without occurring race conditions. This feature is essential for global and static variables accessed from different threads, and program correctness will be preserved. Generally, using atomic type objects is an alternative to locking objects such as mutexes and their standard API functions like mtx_lock
, mtx_unlock
etc. The following code sample demonstrates the counting problem’s simple case, where multiple threads increment a shared global counter variable. Finally, the sum is printed to stdout
at the end of the program. Notice that we declared counter
as usual int
type. Unfortunately, this program is flawed even though some executions may yield correct results.
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
int counter = 0;
enum { MAX_ITER = 10000 };
void incrementCounter(void *thr_id) {
long tid;
tid = (long)thr_id;
printf("thread %ld started incrementing ID - %lu\n", tid, thrd_current());
for (int i = 0; i < MAX_ITER; ++i) {
counter += 1;
}
thrd_exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[]) {
thrd_t threads[NUM_THREADS];
int rc;
long t;
for (t = 0; t < NUM_THREADS; t++) {
rc = thrd_create(&threads[t], (thrd_start_t)incrementCounter, (void *)t);
if (rc == thrd_error) {
printf("ERORR; thrd_create() call failed\n");
exit(EXIT_FAILURE);
}
}
for (t = 0; t < NUM_THREADS; t++) {
thrd_join(threads[t], NULL);
}
printf("count = %d\n", counter);
thrd_exit(EXIT_SUCCESS);
}
Output:
thread 0 started incrementing ID - 140097636923136
thread 2 started incrementing ID - 140097620137728
thread 1 started incrementing ID - 140097628530432
thread 3 started incrementing ID - 140097611745024
count = 18851
Note that the main thread that creates others with the thrd_create
call does not increment the counter variable, so the sum should be multiple of MAX_ITER
constant and NUM_THREADS
denoting the number of threads. One could solve this issue by surrounding the counter += 1
line with mutex locking/unlocking functions or semaphore actions, but in this case, we just declare counter
as the type of atomic_int
. This integer object now is said to have atomic property, implying that any access to it will happen without interruptions, as a single instruction and guaranteeing the program’s sequential execution.
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>
#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif
atomic_int counter = 0;
enum { MAX_ITER = 10000 };
void incrementCounter(void *thr_id) {
long tid;
tid = (long)thr_id;
printf("thread %ld started incrementing ID - %lu\n", tid, thrd_current());
for (int i = 0; i < MAX_ITER; ++i) {
counter += 1;
}
thrd_exit(EXIT_SUCCESS);
}
int main(int argc, char const *argv[]) {
thrd_t threads[NUM_THREADS];
int rc;
long t;
for (t = 0; t < NUM_THREADS; t++) {
rc = thrd_create(&threads[t], (thrd_start_t)incrementCounter, (void *)t);
if (rc == thrd_error) {
printf("ERORR; thrd_create() call failed\n");
exit(EXIT_FAILURE);
}
}
for (t = 0; t < NUM_THREADS; t++) {
thrd_join(threads[t], NULL);
}
printf("count = %d\n", counter);
thrd_exit(EXIT_SUCCESS);
}
Output:
thread 0 started incrementing ID - 140125987915520
thread 1 started incrementing ID - 140125979522816
thread 2 started incrementing ID - 140125971130112
thread 3 started incrementing ID - 140125962737408
count = 40000
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook