v1.0 2024年5月28日 发布于博客园
在嵌入式Linux C编程中,原子性(Atomicity)和非原子性(Non-Atomicity)是非常重要的概念,尤其是在处理多线程或多进程环境时。以下是对这两个概念的详细解释:
原子性(Atomicity)
原子性是指一个操作在执行过程中不可分割,要么完全执行,要么完全不执行。在多线程环境中,原子性操作不会被其他线程的操作打断。
例子:
-
简单的原子操作:
- 一些基本的读写操作在某些架构上是原子的。例如,在许多32位系统上,对32位整数的读写是原子的。
int counter = 0; counter = 1; // 这是一个原子操作(在许多架构上)
-
原子操作函数:
- 在嵌入式Linux中,可以使用GCC提供的内置原子操作函数,如
__sync_fetch_and_add
、__sync_lock_test_and_set
等。
#include <stdio.h> int main() { int counter = 0; __sync_fetch_and_add(&counter, 1); // 原子性加1操作 printf("Counter: %d\n", counter); return 0; }
- 在嵌入式Linux中,可以使用GCC提供的内置原子操作函数,如
-
原子操作库:
- 使用Linux内核提供的原子操作库(atomic operations library),如
atomic_t
类型和相关的操作函数。
#include <linux/atomic.h> atomic_t counter = ATOMIC_INIT(0); void increment_counter() { atomic_inc(&counter); // 原子性加1操作 }
- 使用Linux内核提供的原子操作库(atomic operations library),如
非原子性(Non-Atomicity)
非原子性是指一个操作在执行过程中可能会被其他线程的操作打断。这种操作在多线程环境中可能导致竞争条件(Race Condition),从而引发数据不一致或其他并发问题。
例子:
-
非原子的复合操作:
- 例如,
i++
在许多架构上不是原子的,因为它实际上由多个步骤组成(读取、修改和写入)。
int counter = 0; counter++; // 这是一个非原子操作
- 例如,
-
竞争条件:
- 当多个线程同时执行非原子操作时,可能会导致不可预测的结果。
#include <pthread.h> #include <stdio.h> int counter = 0; void* increment(void* arg) { for (int i = 0; i < 10000; i++) { counter++; // 非原子操作,可能导致竞争条件 } return NULL; } int main() { pthread_t t1, t2; pthread_create(&t1, NULL, increment, NULL); pthread_create(&t2, NULL, increment, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); printf("Counter: %d\n", counter); // 结果可能不正确 return 0; }
确保原子性的方法
-
使用原子操作函数:
- 使用GCC内置的原子操作函数,如
__sync_fetch_and_add
、__sync_lock_test_and_set
等。
- 使用GCC内置的原子操作函数,如
-
使用原子操作库:
- 使用Linux内核提供的原子操作库(atomic operations library)。
-
使用互斥锁(Mutex):
- 使用互斥锁来保护非原子操作,确保在多线程环境中操作的原子性。
#include <pthread.h> #include <stdio.h> int counter = 0; pthread_mutex_t lock; void* increment(void* arg) { for (int i = 0; i < 10000; i++) { pthread_mutex_lock(&lock); counter++; // 受互斥锁保护,确保原子性 pthread_mutex_unlock(&lock); } return NULL; } int main() { pthread_t t1, t2; pthread_mutex_init(&lock, NULL); pthread_create(&t1, NULL, increment, NULL); pthread_create(&t2, NULL, increment, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); pthread_mutex_destroy(&lock); printf("Counter: %d\n", counter); // 结果正确 return 0; }
总结
- 原子性:操作不可分割,要么全部执行,要么全部不执行,确保数据一致性和线程安全。
- 非原子性:操作可能被打断,可能导致数据不一致,需要额外的同步机制来确保线程安全。
在嵌入式Linux C编程中,理解和正确使用原子性和非原子性对于编写安全有效的并发程序至关重要。
标签:int,什么,counter,原子,pthread,操作,NULL From: https://www.cnblogs.com/zqingyang/p/18217958