What is the _Atomic keyword in C?

Share

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.

Syntax

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;

Examples

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 variable
int count = 0;
// the function which will run in the thread
void* runner()
{
for(int i = 0; i < 1000; i++) {
count++;
atomic_count++;
}
return 0;
}
int main()
{
// making the essential variables to create threads
pthread_t threadIDs[5];
pthread_attr_t attr;
pthread_attr_init(&attr);
// making 5 threads
for(int i = 0; i < 8; i++)
pthread_create(&threadIDs[i], &attr, runner, NULL);
// waiting for all threads to finish
for(int i = 0; i < 8; i++)
pthread_join(threadIDs[i], NULL);
// printing the variables
printf("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 sum
int sum = 0;
//pointer to a list of numbers
int* numberList;
// the function which will run in the thread
void* 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' space
numberList = (int*) calloc(5000, sizeof(int));
// setting random values (less than 20) on each index
for(int i=0; i<5000; i++)
{
numberList[i] = rand() % 20;
}
// making the essential variables to create threads
pthread_t threadIDs[5];
pthread_attr_t attr;
pthread_attr_init(&attr);
// making 5 threads
for(int i = 0; i < 5; i++)
pthread_create(&threadIDs[i], &attr, runner, &i);
// waiting for all threads to finish
for(int i = 0; i < 5; i++)
pthread_join(threadIDs[i], NULL);
// printing the variables
printf("The atomic counter is %u\n", atomic_sum);
printf("The non-atomic counter is %u\n", sum);
}
Copyright ©2024 Educative, Inc. All rights reserved