In C, _Atomic
is used as a type specifier. It is used to avoid the race condition if more than one thread attempts to update a variable simultaneously. It is defined in the stdatomic.h
header.
An atomic variable can be declared by using the _Atomic
keyword before declaring it. The snippet of code below shows two different methods to declare an atomic int
variable.
// 1st method
_Atomic int var;
// 2nd method
atomic_int var;
One very common example is shown in the snippet of code below. We are declaring an atomic integer and a simple integer and initializing their values to 0. We are making five threads in the main
function, and each thread will execute the runner
function. A loop increments both the variables by 1 in a thousand iterations in the’ runner’ function.
After the execution of the code, the value for both variables is expected to be 8000, but this is not the case in the output. The value for the atomic variable reaches 8000, but the value for the non-atomic variable does not. This happens due to the instances when more than one threads access the non-atomic variable simultaneously, increments in the same value, and writes it. Due to this, the increment operations in two individual threads bring the effect of one increment operation in the variable’s value.
In the case of the atomic variable, the race condition is avoided because more than one thread is not allowed to access the variable simultaneously.
#include <stdio.h>#include <pthread.h>#include <stdatomic.h>// making an atomic counter_Atomic int atomic_count = 0;// making a simple variableint count = 0;// the function which will run in the threadvoid* runner(){for(int i = 0; i < 1000; i++) {count++;atomic_count++;}return 0;}int main(){// making the essential variables to create threadspthread_t threadIDs[5];pthread_attr_t attr;pthread_attr_init(&attr);// making 5 threadsfor(int i = 0; i < 8; i++)pthread_create(&threadIDs[i], &attr, runner, NULL);// waiting for all threads to finishfor(int i = 0; i < 8; i++)pthread_join(threadIDs[i], NULL);// printing the variablesprintf("The atomic counter is %u\n", atomic_count);printf("The non-atomic counter is %u\n", count);}
In the following snippet of code, we’re attempting to find the sum of five thousand numbers in an array with the help of threads. We’re creating five threads, and each thread will update the sum for a thousand numbers.
After the execution of the code, the atomic variable named atomic_sum
contains the correct sum value. In contrast, the non-atomic variable sum
might not have an accurate value due to the race condition.
#include <stdio.h>#include<stdlib.h>#include <pthread.h>#include <stdatomic.h>// making an atomic integer for sum_Atomic int atomic_sum = 0;// making a simple variable for sumint sum = 0;//pointer to a list of numbersint* numberList;// the function which will run in the threadvoid* runner(void* params){int* ptr = (int*) params;int index = *ptr;int startingIndex = index*1000;for(int i = startingIndex; i < startingIndex + 1000; i++) {sum = sum + numberList[i];atomic_sum = atomic_sum + numberList[i];}return 0;}int main(){// allocating 5000 integers' spacenumberList = (int*) calloc(5000, sizeof(int));// setting random values (less than 20) on each indexfor(int i=0; i<5000; i++){numberList[i] = rand() % 20;}// making the essential variables to create threadspthread_t threadIDs[5];pthread_attr_t attr;pthread_attr_init(&attr);// making 5 threadsfor(int i = 0; i < 5; i++)pthread_create(&threadIDs[i], &attr, runner, &i);// waiting for all threads to finishfor(int i = 0; i < 5; i++)pthread_join(threadIDs[i], NULL);// printing the variablesprintf("The atomic counter is %u\n", atomic_sum);printf("The non-atomic counter is %u\n", sum);}
Free Resources