linux多线程同步的几种方式是什么

来源:网络学院作者:沙月恵奈‌头衔:网络博主
导读:本期聚焦于小伙伴创作的《linux多线程同步的几种方式是什么》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《linux多线程同步的几种方式是什么》有用,将其分享出去将是对创作者最好的鼓励。

在linux系统下的多线程编程场景中,多个线程并发执行时如果同时访问和修改共享资源,很容易出现数据不一致、逻辑错误等问题,线程同步就是用来解决这类问题的核心手段,通过协调线程的执行顺序,保证共享资源在同一时间只被一个或一组线程安全访问。

linux多线程同步的几种方式是什么

linux多线程同步的常见方式

1. 互斥锁(mutex)

互斥锁是最基础的线程同步方式,它的核心逻辑是同一时间只允许一个线程持有锁,其他尝试获取锁的线程会被阻塞,直到持有锁的线程释放锁。互斥锁适合保护需要互斥访问的共享资源,比如全局变量、共享内存区域等。

使用互斥锁需要先初始化锁,然后在访问共享资源前后分别加锁和解锁,最后销毁锁。下面是pthread库互斥锁的使用示例:

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

// 定义共享资源和互斥锁
int shared_num = 0;
pthread_mutex_t mutex;

// 线程执行函数
void* thread_func(void* arg) {
    for (int i = 0; i < 10000; i++) {
        // 加锁
        pthread_mutex_lock(&mutex);
        shared_num++;
        // 解锁
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;
    // 初始化互斥锁
    pthread_mutex_init(&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: %dn", shared_num);
    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);
    return 0;
}

2. 条件变量(condition_variable)

条件变量通常和互斥锁配合使用,用于线程之间的条件等待和通知。当一个线程需要满足某个条件才能继续执行时,它可以等待在条件变量上,另一个线程在条件满足时通知等待的线程。条件变量适合生产者消费者这类场景,比如一个线程生产数据,另一个线程等待数据就绪后再处理。

下面是条件变量配合互斥锁实现简单生产者消费者的示例:

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

// 定义共享数据、互斥锁、条件变量
int data = 0;
int has_data = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;

// 生产者线程函数
void* producer_func(void* arg) {
    for (int i = 0; i < 5; i++) {
        pthread_mutex_lock(&mutex);
        data = i;
        has_data = 1;
        printf("生产者生产数据: %dn", data);
        // 通知等待条件变量的线程
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

// 消费者线程函数
void* consumer_func(void* arg) {
    for (int i = 0; i < 5; i++) {
        pthread_mutex_lock(&mutex);
        // 等待条件满足,会自动释放锁,被唤醒后重新获取锁
        while (has_data == 0) {
            pthread_cond_wait(&cond, &mutex);
        }
        printf("消费者消费数据: %dn", data);
        has_data = 0;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t producer, consumer;
    // 初始化互斥锁和条件变量
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    // 创建生产者和消费者线程
    pthread_create(&producer, NULL, producer_func, NULL);
    pthread_create(&consumer, NULL, consumer_func, NULL);
    // 等待线程结束
    pthread_join(producer, NULL);
    pthread_join(consumer, NULL);
    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}

3. 信号量(semaphore)

信号量是一个计数器,用于控制同时访问共享资源的线程数量。它支持两种操作,分别是P操作(计数器减1,若计数器为0则阻塞)和V操作(计数器加1,唤醒阻塞的线程)。信号量既可以用于互斥(初始值为1时和互斥锁效果类似),也可以用于控制并发数量,比如限制同时只有3个线程访问某个资源。

下面是使用信号量控制并发访问数量的示例,限制同时只有2个线程执行任务:

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

// 定义信号量
sem_t sem;

// 线程执行函数
void* thread_func(void* arg) {
    // P操作,获取信号量
    sem_wait(&sem);
    printf("线程 %ld 开始执行任务n", (long)arg);
    // 模拟任务执行
    sleep(1);
    printf("线程 %ld 任务执行完成n", (long)arg);
    // V操作,释放信号量
    sem_post(&sem);
    return NULL;
}

int main() {
    pthread_t threads[5];
    // 初始化信号量,初始值为2,最多允许2个线程同时访问
    sem_init(&sem, 0, 2);
    // 创建5个线程
    for (int i = 0; i < 5; i++) {
        pthread_create(&threads[i], NULL, thread_func, (void*)(long)i);
    }
    // 等待所有线程结束
    for (int i = 0; i < 5; i++) {
        pthread_join(threads[i], NULL);
    }
    // 销毁信号量
    sem_destroy(&sem);
    return 0;
}

4. 读写锁(rwlock)

读写锁适合读多写少的场景,它区分读操作和写操作:多个线程可以同时持有读锁进行读操作,但是写锁是互斥的,同一时间只能有一个线程持有写锁,且持有写锁时不能有线程持有读锁。读写锁可以提高读多写少场景下的并发性能,避免读操作之间不必要的互斥。

下面是读写锁的使用示例:

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

// 定义共享数据和读写锁
int shared_data = 0;
pthread_rwlock_t rwlock;

// 读线程函数
void* read_func(void* arg) {
    pthread_rwlock_rdlock(&rwlock);
    printf("读线程 %ld 读取数据: %dn", (long)arg, shared_data);
    pthread_rwlock_unlock(&rwlock);
    return NULL;
}

// 写线程函数
void* write_func(void* arg) {
    pthread_rwlock_wrlock(&rwlock);
    shared_data++;
    printf("写线程 %ld 写入数据: %dn", (long)arg, shared_data);
    pthread_rwlock_unlock(&rwlock);
    return NULL;
}

int main() {
    pthread_t read_threads[3], write_threads[2];
    // 初始化读写锁
    pthread_rwlock_init(&rwlock, NULL);
    // 创建读线程和写线程
    for (int i = 0; i < 3; i++) {
        pthread_create(&read_threads[i], NULL, read_func, (void*)(long)i);
    }
    for (int i = 0; i < 2; i++) {
        pthread_create(&write_threads[i], NULL, write_func, (void*)(long)i);
    }
    // 等待所有线程结束
    for (int i = 0; i < 3; i++) {
        pthread_join(read_threads[i], NULL);
    }
    for (int i = 0; i < 2; i++) {
        pthread_join(write_threads[i], NULL);
    }
    // 销毁读写锁
    pthread_rwlock_destroy(&rwlock);
    return 0;
}

不同同步方式的选择建议

在实际开发中可以根据场景选择合适的同步方式:

  • 如果只是简单的共享资源互斥访问,优先选择互斥锁,实现简单开销小
  • 如果需要线程之间等待某个条件成立,选择条件变量配合互斥锁
  • 如果需要控制并发访问的线程数量,或者实现更复杂的同步逻辑,选择信号量
  • 如果是读多写少的场景,选择读写锁可以提升并发性能

需要注意的是,使用这些同步方式时都要避免死锁问题,比如加锁后一定要记得解锁,不要嵌套获取多个锁时形成循环等待。

linux多线程线程同步mutexcondition_variablesemaphore修改时间:2026-07-16 17:57:40

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