导读:本期聚焦于小伙伴创作的《Linux多线程及多线程并发访问同一块内存的问题怎么解决》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Linux多线程及多线程并发访问同一块内存的问题怎么解决》有用,将其分享出去将是对创作者最好的鼓励。

在Linux环境下进行多线程开发时,多个线程并发访问同一块共享内存是常见场景,若没有合理的同步控制,就会出现竞态条件,导致内存中的数据被错误修改,程序运行结果不符合预期。这类问题的本质是多个线程对共享资源的访问没有顺序约束,执行时序的不确定性会引发数据不一致。

Linux多线程及多线程并发访问同一块内存的问题怎么解决

多线程并发访问内存的常见问题

当多个线程同时读写同一块内存区域时,最常见的两类问题是数据覆盖和中间状态暴露。比如两个线程同时对一个全局计数器做加1操作,正常情况下两次加1后计数器应该增加2,但若没有同步,可能出现两个线程同时读取到旧值,各自加1后写回,最终计数器只增加了1。

这类问题在调试时往往很难复现,因为线程调度顺序是不确定的,只有在特定时序下才会触发异常,所以需要在开发阶段就通过同步机制提前规避。

核心解决方案:同步机制的使用

1. 互斥锁(Mutex)

互斥锁是最常用的同步工具,它的核心逻辑是同一时间只允许一个线程持有锁,访问共享内存,其他线程需要等待锁释放后才能获取锁并访问资源,从根源上避免多个线程同时操作共享内存。

Linux下使用pthread库的互斥锁需要包含<pthread.h>头文件,基本使用流程如下:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 定义共享内存变量
int shared_num = 0;
// 定义互斥锁
pthread_mutex_t shared_mutex;

// 线程执行函数,对共享变量做加1操作
void* thread_func(void* arg) {
    for (int i = 0; i < 10000; i++) {
        // 加锁,若锁已被其他线程持有则阻塞等待
        pthread_mutex_lock(&shared_mutex);
        // 访问共享内存
        shared_num++;
        // 解锁,释放锁给其他线程使用
        pthread_mutex_unlock(&shared_mutex);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;
    // 初始化互斥锁,使用默认属性
    pthread_mutex_init(&shared_mutex, NULL);
    // 创建两个线程
    pthread_create(&t1, NULL, thread_func, NULL);
    pthread_create(&t2, NULL, thread_func, NULL);
    // 等待两个线程执行完成
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    // 输出共享变量结果,预期为20000
    printf("shared_num final value: %dn", shared_num);
    // 销毁互斥锁
    pthread_mutex_destroy(&shared_mutex);
    return 0;
}

上面的代码中,两个线程对shared_num做10000次加1操作,通过互斥锁保证每次加1操作是原子的,最终输出结果会是20000,不会出现数据丢失的情况。

2. 读写锁(RWLock)

如果共享内存的访问场景是读多写少,使用互斥锁会让所有读操作也串行执行,降低效率。这时候可以使用读写锁,它允许多个线程同时读共享内存,但写操作时需要独占锁,同一时间只能有一个线程写,且写的时候不能有线程读。

读写锁的基本使用示例如下:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 共享内存数据
char shared_data[128] = "init data";
// 定义读写锁
pthread_rwlock_t rwlock;

// 读线程函数
void* read_thread(void* arg) {
    for (int i = 0; i < 5; i++) {
        // 加读锁
        pthread_rwlock_rdlock(&rwlock);
        printf("read thread %ld, data: %sn", (long)arg, shared_data);
        // 解读锁
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }
    return NULL;
}

// 写线程函数
void* write_thread(void* arg) {
    for (int i = 0; i < 3; i++) {
        // 加写锁
        pthread_rwlock_wrlock(&rwlock);
        snprintf(shared_data, sizeof(shared_data), "update data %d", i);
        printf("write thread update data to: %sn", shared_data);
        // 解写锁
        pthread_rwlock_unlock(&rwlock);
        sleep(2);
    }
    return NULL;
}

int main() {
    pthread_t r1, r2, w1;
    // 初始化读写锁
    pthread_rwlock_init(&rwlock, NULL);
    // 创建两个读线程和一个写线程
    pthread_create(&r1, NULL, read_thread, (void*)1);
    pthread_create(&r2, NULL, read_thread, (void*)2);
    pthread_create(&w1, NULL, write_thread, NULL);
    // 等待所有线程结束
    pthread_join(r1, NULL);
    pthread_join(r2, NULL);
    pthread_join(w1, NULL);
    // 销毁读写锁
    pthread_rwlock_destroy(&rwlock);
    return 0;
}

3. 条件变量(Condition Variable)

条件变量通常和互斥锁配合使用,用于解决线程间的同步问题,比如一个线程需要等待另一个线程修改共享内存到某个状态后再继续执行。典型场景是生产者消费者模型,生产者线程往共享队列写数据,消费者线程等待队列有数据后再读取。

条件变量的使用示例:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

// 共享队列,最多存5个元素
int queue[5];
int queue_size = 0;
// 互斥锁和条件变量
pthread_mutex_t queue_mutex;
pthread_cond_t queue_not_empty;
pthread_cond_t queue_not_full;

// 生产者线程函数
void* producer(void* arg) {
    int num = 0;
    while (1) {
        pthread_mutex_lock(&queue_mutex);
        // 队列满了就等待条件变量
        while (queue_size == 5) {
            pthread_cond_wait(&queue_not_full, &queue_mutex);
        }
        // 往队列写数据
        queue[queue_size] = num++;
        queue_size++;
        printf("producer add num: %d, queue size: %dn", queue[queue_size-1], queue_size);
        // 通知消费者队列不为空
        pthread_cond_signal(&queue_not_empty);
        pthread_mutex_unlock(&queue_mutex);
        sleep(1);
    }
    return NULL;
}

// 消费者线程函数
void* consumer(void* arg) {
    while (1) {
        pthread_mutex_lock(&queue_mutex);
        // 队列空了就等待条件变量
        while (queue_size == 0) {
            pthread_cond_wait(&queue_not_empty, &queue_mutex);
        }
        // 从队列读数据
        int val = queue[0];
        for (int i = 0; i < queue_size - 1; i++) {
            queue[i] = queue[i+1];
        }
        queue_size--;
        printf("consumer get num: %d, queue size: %dn", val, queue_size);
        // 通知生产者队列不满
        pthread_cond_signal(&queue_not_full);
        pthread_mutex_unlock(&queue_mutex);
        sleep(2);
    }
    return NULL;
}

int main() {
    pthread_t p, c;
    // 初始化互斥锁和条件变量
    pthread_mutex_init(&queue_mutex, NULL);
    pthread_cond_init(&queue_not_empty, NULL);
    pthread_cond_init(&queue_not_full, NULL);
    // 创建生产者和消费者线程
    pthread_create(&p, NULL, producer, NULL);
    pthread_create(&c, NULL, consumer, NULL);
    // 等待线程(实际场景可加退出逻辑)
    pthread_join(p, NULL);
    pthread_join(c, NULL);
    // 销毁资源
    pthread_mutex_destroy(&queue_mutex);
    pthread_cond_destroy(&queue_not_empty);
    pthread_cond_destroy(&queue_not_full);
    return 0;
}

不同场景的方案选择

如果共享内存的访问是简单的读写操作,且读写频率差不多,优先选择互斥锁,实现简单且可靠性高。如果是读多写少的场景,读写锁能提升整体性能。如果线程之间需要基于共享内存的状态做协作,比如等待某个条件成立再执行,就需要配合条件变量使用。

另外需要注意,所有同步工具都需要正确初始化和销毁,避免资源泄漏。加锁的范围要尽量小,只包裹操作共享内存的代码段,减少锁持有的时间,避免影响程序并发性能。

Linux多线程并发访问互斥锁条件变量内存同步修改时间:2026-07-19 01:30:37

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。