linux——原子操作

一、原子操作概念

1. 什么是原子操作?

原子操作 = 不可被中断的操作就像原子是不可分割的最小单位一样。

CPU 执行原子操作时:

  • 一步完成
  • 执行期间不会被线程切换打断
  • 要么完全执行完,要么完全没执行
  • 不会出现 "执行一半被抢走 CPU" 的情况

2. 哪些是原子操作?

  • 简单赋值:a = 100;
  • 简单读取:int b = a;

3. 哪些 不是 原子操作?

这些操作会被线程打断:

  • a = b + 100; (读 → 算 → 写,三步)
  • i++; (读 → 加 → 写)
  • 链表插入、链表删除
  • printf() 不是原子操作(内部复杂)
  • malloc/free 不是原子操作

只要不是一步 CPU 指令,就不是原子操作!

二、为什么非原子操作必须加锁?

因为:非原子操作 = 多步指令 = 可能执行到一半被抢走 CPU一旦被抢走,数据就会错乱、崩溃、覆盖、丢失。

三、用两个示例代码讲清楚

我们以链表头插法为例:

复制代码
newNode->next = head;
head = newNode;

这两行代码 不是原子操作!必须连续执行,不能被打断。

示例代码 1:不加锁(错误!)

复制代码
void* producer(void *arg)
{
    while(1)
    {
        // 创建节点(原子与否不重要)
        Node *newNode = (Node*)malloc(sizeof(Node));
        newNode->data = rand()%100;

        // ==========================
        // 这两行不是原子操作!!!
        newNode->next = head;
        head = newNode;
        // ==========================

        printf("+++product: %d\n", newNode->data);

        sleep(rand()%3);
    }
    return NULL;
}

错误原因:

newNode->next = head;head = newNode;不是原子操作!

两个线程同时执行时,可能:

  • 线程 A 刚执行完第一行

  • CPU 被抢走

  • 线程 B 也修改 head

  • 回来后线程 A 继续执行 → 链表断了、节点丢了、程序崩溃!

结论:

多线程同时操作链表,不加锁 = 程序必定崩溃 / 数据错乱

示例代码 2:加锁(正确!)

复制代码
void* producer(void *arg)
{
    while(1)
    {
        Node *newNode = (Node*)malloc(sizeof(Node));
        newNode->data = rand()%100;

        // 加锁(开始原子区)
        pthread_mutex_lock(&mutex);

        // 这两行被锁保护 → 变成逻辑原子
        newNode->next = head;
        head = newNode;
        printf("+++product: %d\n", newNode->data);

        // 解锁
        pthread_mutex_unlock(&mutex);

        sleep(rand()%3);
    }
    return NULL;
}

锁把两行代码变成 "逻辑原子操作"

  • 同一时间只有一个线程能执行
  • 执行时不会被其他线程打断
  • 要么两行都执行完,要么都不执行
  • 链表永远安全、不会崩溃、不会断链

四、核心总结

  1. 原子操作:不可被中断的一步操作
  2. 多步操作(链表增删、i++)不是原子操作
  3. 非原子操作在多线程下必须加锁
  4. 锁可以让多步指令变成 "逻辑上的原子操作"
  5. 不加锁 = 线程切换打断 = 数据混乱 / 程序崩溃
  6. 加锁 = 安全执行 = 逻辑原子
相关推荐
Eminem8911 分钟前
2、k8s环境规划
linux·运维·kubernetes
打团从来人不齐36 分钟前
Linux服务器搭建笔记-008:台式机共享WIFI
linux·服务器·笔记
w200512241 小时前
K8S控制器管理
linux·云原生·容器·kubernetes
Dream Cosmos1 小时前
Linux 多线程——线程互斥:从抢票问题到 Mutex 底层原理
linux·c++
玖石书2 小时前
Ubuntu 更换 USTC 镜像源完整指南(AMD64 / AARCH64)
linux·运维·ubuntu
zbyyd2 小时前
Linux 进程间通信(IPC):信号、消息队列、共享内存与信号量详解
linux·运维·c语言
yunwei372 小时前
AgentCgroup:当 AI Agent 遇到操作系统资源
linux·人工智能·后端
闲云野鹤在人间3 小时前
KVM虚拟化实战|CentOS‑Stream8 两种安装方式+模板制作+基础使用
linux·运维·服务器·centos
小张同学a.3 小时前
Docker 容器实战 2—— docker 仓库
linux·运维·服务器·docker·容器
Android系统攻城狮3 小时前
Linux PipeWire深度解析之pw_core_get_registry调用流程与实战(九十一)
linux·运维·服务器·音频进阶·pipewire音频实战进阶