Linux实现线程同步有几种方式

来源:Python编程网作者:韦伯头衔:草根站长
导读:本期聚焦于小伙伴创作的《Linux实现线程同步有几种方式》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Linux实现线程同步有几种方式》有用,将其分享出去将是对创作者最好的鼓励。

在Linux多线程编程中,当多个线程同时访问共享资源时,很容易出现数据竞争问题,导致程序运行结果不符合预期,因此需要通过线程同步机制来协调线程的执行顺序,保证共享资源在同一时间只被一个或一组线程访问。

互斥锁

互斥锁是最常用的线程同步方式,它的核心作用是保证同一时间只有一个线程能够持有锁并访问共享资源,其他尝试获取锁的线程会被阻塞,直到锁被释放。

互斥锁的使用步骤通常分为初始化、加锁、访问共享资源、解锁、销毁五个部分,下面是使用POSIX线程库的互斥锁示例:

#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);
    // 打印共享资源结果
    printf("shared_num result: %dn", shared_num);
    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);
    return 0;
}

条件变量

条件变量通常和互斥锁配合使用,用于在线程之间同步共享数据状态的变化,当某个条件不满足时,线程可以等待条件变量,直到其他线程修改了共享数据并通知条件变量,等待的线程才会被唤醒继续执行。

常见的使用场景是生产者消费者模型,下面是条件变量的使用示例:

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

// 定义共享缓冲区
int buffer = 0;
// 定义互斥锁和条件变量
pthread_mutex_t mutex;
pthread_cond_t cond;

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

// 消费者线程函数
void* consumer(void* arg) {
    for (int i = 0; i < 5; i++) {
        pthread_mutex_lock(&mutex);
        // 等待条件满足,避免虚假唤醒,使用while循环判断
        while (buffer == 0) {
            pthread_cond_wait(&cond, &mutex);
        }
        printf("消费者消费数据: %dn", buffer);
        buffer = 0;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

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

信号量

信号量是一个计数器,用于控制多个线程对共享资源的访问,它支持同时多个线程访问共享资源,计数器的初始值表示可以同时访问资源的线程数量,线程访问资源前需要对信号量做P操作(减1),访问完成后做V操作(加1),当计数器为0时,尝试P操作的线程会被阻塞。

信号量分为无名信号量和有名信号量,下面是无名信号量的使用示例,同样实现生产者消费者逻辑:

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

// 定义共享缓冲区
int buffer = 0;
// 定义信号量,empty表示空缓冲区数量,full表示满缓冲区数量
sem_t empty, full;
pthread_mutex_t mutex;

// 生产者线程函数
void* producer(void* arg) {
    for (int i = 0; i < 5; i++) {
        // 申请空缓冲区,P操作
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);
        buffer = i;
        printf("生产者生产数据: %dn", buffer);
        pthread_mutex_unlock(&mutex);
        // 释放满缓冲区,V操作
        sem_post(&full);
        sleep(1);
    }
    return NULL;
}

// 消费者线程函数
void* consumer(void* arg) {
    for (int i = 0; i < 5; i++) {
        // 申请满缓冲区,P操作
        sem_wait(&full);
        pthread_mutex_lock(&mutex);
        printf("消费者消费数据: %dn", buffer);
        buffer = 0;
        pthread_mutex_unlock(&mutex);
        // 释放空缓冲区,V操作
        sem_post(&empty);
    }
    return NULL;
}

int main() {
    pthread_t prod, cons;
    // 初始化信号量,empty初始值为1表示有1个空缓冲区,full初始值为0表示没有满缓冲区
    sem_init(&empty, 0, 1);
    sem_init(&full, 0, 0);
    pthread_mutex_init(&mutex, NULL);
    // 创建线程
    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);
    // 等待线程执行完成
    pthread_join(prod, NULL);
    pthread_join(cons, NULL);
    // 销毁信号量和互斥锁
    sem_destroy(&empty);
    sem_destroy(&full);
    pthread_mutex_destroy(&mutex);
    return 0;
}

读写锁

读写锁适用于读操作远多于写操作的场景,它允许多个线程同时持有读锁进行读操作,但是同一时间只能有一个线程持有写锁进行写操作,并且当有线程持有写锁时,其他线程无法获取读锁或写锁,当有线程持有读锁时,其他线程可以获取读锁但无法获取写锁。

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

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

// 定义共享资源
int shared_data = 0;
// 定义读写锁
pthread_rwlock_t rwlock;

// 读线程函数
void* reader(void* arg) {
    int thread_id = *(int*)arg;
    pthread_rwlock_rdlock(&rwlock);
    printf("读线程%d读取数据: %dn", thread_id, shared_data);
    pthread_rwlock_unlock(&rwlock);
    return NULL;
}

// 写线程函数
void* writer(void* arg) {
    int thread_id = *(int*)arg;
    pthread_rwlock_wrlock(&rwlock);
    shared_data += 10;
    printf("写线程%d修改数据,当前值: %dn", thread_id, shared_data);
    pthread_rwlock_unlock(&rwlock);
    return NULL;
}

int main() {
    pthread_t readers[3], writers[2];
    int reader_ids[3] = {1,2,3};
    int writer_ids[2] = {1,2};
    // 初始化读写锁
    pthread_rwlock_init(&rwlock, NULL);
    // 创建读线程和写线程
    for (int i = 0; i < 3; i++) {
        pthread_create(&readers[i], NULL, reader, &reader_ids[i]);
    }
    for (int i = 0; i < 2; i++) {
        pthread_create(&writers[i], NULL, writer, &writer_ids[i]);
    }
    // 等待所有线程执行完成
    for (int i = 0; i < 3; i++) {
        pthread_join(readers[i], NULL);
    }
    for (int i = 0; i < 2; i++) {
        pthread_join(writers[i], NULL);
    }
    // 销毁读写锁
    pthread_rwlock_destroy(&rwlock);
    return 0;
}

不同同步方式的适用场景

不同的线程同步方式有不同的适用场景,开发者可以根据实际需求选择:

  • 互斥锁适合简单的共享资源互斥访问场景,实现简单,开销较小
  • 条件变量适合需要等待某个条件满足的场景,通常和互斥锁配合使用
  • 信号量适合控制同时访问共享资源的线程数量,也可以用于线程间的顺序同步
  • 读写锁适合读多写少的场景,可以提升程序的并发性能

在实际开发中,需要根据具体的业务场景选择合适的同步方式,同时要注意避免死锁问题,比如保证加锁和解锁成对出现,按照固定的顺序获取多个锁等。

Linux线程同步互斥锁条件变量信号量读写锁修改时间:2026-06-12 01:39:45

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