TUTORIALS 》 Linux user-space Atomic Operations via GCC Atomic builtins
Atomic operations provide instructions that execute atomically without interruption. We all know the existence and significance of
ATOMIC operations in Linux Kernel context
(refer: atomic.h source).
This is a part of kernel space can not work on user-space.
User space Atomic Operations :: GCC Atomic builtins: Not many are aware of the feasibility of Linux user-space Atomic operations.
If you investigate you find what is known as GCC inbuilts. For example: /usr/include/glib-2.0/glib/gatomic.h
Article: Atomic Operations - Where did atomic.h go?!? There is an author who did abstraction of these GCC Atomic builtins and wrote high-level
abstraction to use the same with ease. Here is his article titled
Atomic Operations - Where did atomic.h go?!?
Here is the copy-paste of his source (atomic.h) for quick reference:
//Source: http://golubenco.org/atomic-operations.html #ifndef _ATOMIC_H #define _ATOMIC_H /* Check GCC version, just to be safe */ #if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC_MINOR__ < 1) # error atomic.h works only with GCC newer than version 4.1 #endif /* GNUC >= 4.1 */ /** * Atomic type. */ typedef struct { volatile int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } /** * Read atomic variable * @param v pointer of type atomic_t * * Atomically reads the value of @v. */ #define atomic_read(v) ((v)->counter) /** * Set atomic variable * @param v pointer of type atomic_t * @param i required value */ #define atomic_set(v,i) (((v)->counter) = (i)) /** * Add to the atomic variable * @param i integer value to add * @param v pointer of type atomic_t */ static inline void atomic_add( int i, atomic_t *v ) { (void)__sync_add_and_fetch(&v->counter, i); } /** * Subtract the atomic variable * @param i integer value to subtract * @param v pointer of type atomic_t * * Atomically subtracts @i from @v. */ static inline void atomic_sub( int i, atomic_t *v ) { (void)__sync_sub_and_fetch(&v->counter, i); } /** * Subtract value from variable and test result * @param i integer value to subtract * @param v pointer of type atomic_t * * Atomically subtracts @i from @v and returns * true if the result is zero, or false for all * other cases. */ static inline int atomic_sub_and_test( int i, atomic_t *v ) { return !(__sync_sub_and_fetch(&v->counter, i)); } /** * Increment atomic variable * @param v pointer of type atomic_t * * Atomically increments @v by 1. */ static inline void atomic_inc( atomic_t *v ) { (void)__sync_fetch_and_add(&v->counter, 1); } /** * @brief decrement atomic variable * @param v: pointer of type atomic_t * * Atomically decrements @v by 1. Note that the guaranteed * useful range of an atomic_t is only 24 bits. */ static inline void atomic_dec( atomic_t *v ) { (void)__sync_fetch_and_sub(&v->counter, 1); } /** * @brief Decrement and test * @param v pointer of type atomic_t * * Atomically decrements @v by 1 and * returns true if the result is 0, or false for all other * cases. */ static inline int atomic_dec_and_test( atomic_t *v ) { return !(__sync_sub_and_fetch(&v->counter, 1)); } /** * @brief Increment and test * @param v pointer of type atomic_t * * Atomically increments @v by 1 * and returns true if the result is zero, or false for all * other cases. */ static inline int atomic_inc_and_test( atomic_t *v ) { return !(__sync_add_and_fetch(&v->counter, 1)); } /** * @brief add and test if negative * @param v pointer of type atomic_t * @param i integer value to add * * Atomically adds @i to @v and returns true * if the result is negative, or false when * result is greater than or equal to zero. */ static inline int atomic_add_negative( int i, atomic_t *v ) { return (__sync_add_and_fetch(&v->counter, i) < 0); } #endif
You can download the above source (atomic.h) HERE.
Ramin (one of my students), who solely did this entire study/research and to confirm the GCC Atomic built-ins and the atomic.h abstraction layer, wrote the below sample code to test some of the APIs/features:
//Author : Ramin Farajpour Cami #include "atomic.h" #include <stdio.h> int main(){ atomic_t v; /* define v */ atomic_t u = ATOMIC_INIT(0); /* define u and initialize it to zero */ atomic_set(&v, 4); /* v = 4 (atomically) */ printf("%d\n", atomic_read(&v)); atomic_add(2, &v); /* v = v + 2 = 6 (atomically) */ printf("%d\n", atomic_read(&v)); atomic_inc(&v); /* v = v + 1 = 7 (atomically) */ printf("%d\n", atomic_read(&v)); return 0; }
You can download the above source (main.c) HERE.
You can now compile and test the same as shown below:
kiran@WD-1TB2:/backups/Ramin/atomic_t$ ls atomic.h main.c kiran@WD-1TB2:/backups/Ramin/atomic_t$ gcc -o main main.c kiran@WD-1TB2:/backups/Ramin/atomic_t$ ls atomic.h main main.c kiran@WD-1TB2:/backups/Ramin/atomic_t$ ./main 4 6 7 kiran@WD-1TB2:/backups/Ramin/atomic_t$
Run-time performance of various synchronization mechanism: A random find by Saravanan (one of my students), found an article where the
author Alexander Demin, a Russian programmer,
did interesting research on performance of various synchronization mechanisms. You can read his detailed article/research titled:
Comparing the performance of atomic, spinlock and mutex.
And here is his benchmarks:
Method | Time (sec.) |
---|---|
No synchronization | 0.070 |
LOCK | 0.481 |
Atomic | 0.457 |
Spinlock | 0.541 |
Mutex | 22.667 |
So this way you can use Atomic variables either directly or via abstraction layer in regular user-space Linux C programming. You can further experiment atomic operations in your concurrent multi-threaded applications where synchronization and data-integrity is critical.
Featured Video:
Suggested Topics:
Join The Linux Channel :: Facebook Group ↗
Visit The Linux Channel :: on Youtube ↗
💗 Help shape the future: Sponsor/Donate
Recommended Topics:
Featured Video:
Trending Video:
Recommended Video: