当前位置: 首页 > article >正文

Linux下线程间同步实现方式详解

目录

概述

1. 互斥锁(Mutex)

2. 条件变量(Condition Variable)

3. 信号量(Semaphore)

4. 读写锁(Read-Write Lock)

5. 屏障(Barrier)

6. 自旋锁(Spinlock)

7. 线程局部存储(Thread-Local Storage, TLS)

总结


概述

Linux 中线程(Thread)是共享进程内存空间的轻量级执行单元,线程间通信(IPC)主要通过 共享内存 和 同步机制 实现。在Linux操作系统中,线程间实现同步通信的方式主要包括互斥锁(Mutex)、条件变量(Condition Variable)、信号量(Semaphore)、读写锁(Read-Write Lock)等。以下是常用方式及其原理、场景和代码示例。

1. 互斥锁(Mutex)

原理

  • 通过锁机制保护共享资源,同一时间仅允许一个线程访问临界区。

  • 线程在进入临界区前加锁,退出时解锁。

适用场景

  • 保护共享变量、数据结构等临界资源。

  • 防止数据竞争(Data Race)。

C 语言示例

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

pthread_mutex_t mutex;
int counter = 0;

void* thread_func(void* arg) {
    pthread_mutex_lock(&mutex); // 加锁
    counter++;
    printf("Counter: %d\n", counter);
    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);
    pthread_mutex_destroy(&mutex);
    return 0;
}

2. 条件变量(Condition Variable)

原理

  • 允许线程在条件不满足时阻塞,等待其他线程发送信号唤醒。

  • 必须与互斥锁配合使用,避免竞争条件。

适用场景

  • 生产者-消费者模型。

  • 线程间状态同步(如任务队列空/满)。

C 语言示例

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

pthread_mutex_t mutex;
pthread_cond_t cond;
int data_ready = 0;

void* producer(void* arg) {
    pthread_mutex_lock(&mutex);
    data_ready = 1;
    printf("Producer: 数据已生成\n");
    pthread_cond_signal(&cond); // 发送信号
    pthread_mutex_unlock(&mutex);
    return NULL;
}

void* consumer(void* arg) {
    pthread_mutex_lock(&mutex);
    while (!data_ready) {
        pthread_cond_wait(&cond, &mutex); // 等待信号
    }
    printf("Consumer: 收到数据\n");
    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;
}

3. 信号量(Semaphore)

原理

  • 通过计数器控制资源访问,支持 P(等待,计数器减)和 V(释放,计数器加)操作。

  • 可以解决多线程同步问题,支持多个线程同时访问有限资源。

适用场景

  • 控制资源池(如数据库连接池)。

  • 限制并发线程数量。

C 语言示例

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

sem_t sem;
int shared_data = 0;

void* thread_func(void* arg) {
    sem_wait(&sem); // P 操作
    shared_data++;
    printf("Thread %ld: shared_data = %d\n", (long)arg, shared_data);
    sem_post(&sem); // V 操作
    return NULL;
}

int main() {
    sem_init(&sem, 0, 1); // 初始值为1(二进制信号量)
    pthread_t t1, t2;
    pthread_create(&t1, NULL, thread_func, (void*)1);
    pthread_create(&t2, NULL, thread_func, (void*)2);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    sem_destroy(&sem);
    return 0;
}

4. 读写锁(Read-Write Lock)

原理

  • 允许多个读线程同时访问共享资源,但写线程独占访问。

  • 读优先或写优先策略可选。

适用场景

  • 读多写少的场景(如配置管理、缓存系统)。

C 语言示例

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

pthread_rwlock_t rwlock;
int data = 0;

void* reader(void* arg) {
    pthread_rwlock_rdlock(&rwlock); // 读锁
    printf("Reader: data = %d\n", data);
    pthread_rwlock_unlock(&rwlock);
    return NULL;
}

void* writer(void* arg) {
    pthread_rwlock_wrlock(&rwlock); // 写锁
    data++;
    printf("Writer: 更新 data 为 %d\n", data);
    pthread_rwlock_unlock(&rwlock);
    return NULL;
}

int main() {
    pthread_rwlock_init(&rwlock, NULL);
    pthread_t r1, r2, w;
    pthread_create(&r1, NULL, reader, NULL);
    pthread_create(&w, NULL, writer, NULL);
    pthread_create(&r2, NULL, reader, NULL);
    pthread_join(r1, NULL);
    pthread_join(w, NULL);
    pthread_join(r2, NULL);
    pthread_rwlock_destroy(&rwlock);
    return 0;
}

5. 屏障(Barrier)

原理

  • 使多个线程在某个点同步,所有线程到达屏障后继续执行。

适用场景

  • 并行计算中分阶段处理(如 MapReduce)。

C 语言示例

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

pthread_barrier_t barrier;

void* task(void* arg) {
    printf("线程 %ld 执行第一阶段\n", (long)arg);
    pthread_barrier_wait(&barrier); // 等待所有线程到达
    printf("线程 %ld 执行第二阶段\n", (long)arg);
    return NULL;
}

int main() {
    pthread_barrier_init(&barrier, NULL, 3); // 等待3个线程
    pthread_t t1, t2, t3;
    pthread_create(&t1, NULL, task, (void*)1);
    pthread_create(&t2, NULL, task, (void*)2);
    pthread_create(&t3, NULL, task, (void*)3);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_barrier_destroy(&barrier);
    return 0;
}

6. 自旋锁(Spinlock)

原理

  • 线程在等待锁时不会休眠,而是循环检查锁状态(忙等待)。

  • 适用于锁持有时间短的场景。

适用场景

  • 内核编程或实时系统。

  • 避免线程切换开销。

C 语言示例

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

pthread_spinlock_t spinlock;
int counter = 0;

void* thread_func(void* arg) {
    pthread_spin_lock(&spinlock);
    counter++;
    printf("Counter: %d\n", counter);
    pthread_spin_unlock(&spinlock);
    return NULL;
}

int main() {
    pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);
    pthread_t t1, t2;
    pthread_create(&t1, NULL, thread_func, NULL);
    pthread_create(&t2, NULL, thread_func, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_spin_destroy(&spinlock);
    return 0;
}

7. 线程局部存储(Thread-Local Storage, TLS)

原理

  • 每个线程拥有变量的独立副本,互不干扰。

  • 使用 __thread 关键字或 pthread_key_create 实现。

适用场景

  • 需要线程私有数据(如错误码、日志上下文)。

C 语言示例

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

__thread int tls_var = 0; // GCC 扩展语法

void* thread_func(void* arg) {
    tls_var = (int)(long)arg;
    printf("线程 %ld: tls_var = %d\n", (long)arg, tls_var);
    return NULL;
}

int main() {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, thread_func, (void*)1);
    pthread_create(&t2, NULL, thread_func, (void*)2);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    return 0;
}

总结

对比如下

根据具体场景选择合适的同步机制,例如:

  • 高并发读 → 读写锁。

  • 短临界区 → 自旋锁。

  • 多阶段任务 → 屏障。

 


http://www.kler.cn/a/534072.html

相关文章:

  • 数据结构:时间复杂度
  • RocketMQ实战—4.消息零丢失的方案
  • SpringSecurity密码编码器:使用BCrypt算法加密、自定义密码编码器
  • Mac mini m4本地跑大模型(ollama + llama + ComfyUI + Stable Diffusion | flux)
  • 除了网页,还有哪些方式可以访问deepseek r1
  • 前端学习数据库知识
  • ZooKeeper单节点详细部署流程
  • 【Kubernetes Pod间通信-第3篇】Kubernetes中Pod与ClusterIP服务之间的通信
  • OSPF基础(1)
  • JDK 中 NIO 框架设计与实现:深入剖析及实战样例
  • DES 3DES 简介 以及 C# 和 js 实现【加密知多少系列_2】
  • 以太网总线多功能数据采集卡,16路2M同步模拟量采集卡 NET9784A/B
  • 《Python预训练视觉和大语言模型》:从DeepSeek到大模型实战的全栈指南
  • Go语言的转义字符
  • LeetCode - #198 打家劫舍
  • Matplotlib 高级图表绘制与交互式可视化(mpld3)
  • springboot+vue+uniapp的校园二手交易小程序
  • 大模型技术对大数据生态链的全面革新
  • SQL中的三值逻辑和NULL
  • 蓝桥杯更小的数(区间DP)
  • 【Elasticsearch】单桶聚合与多桶聚合的区别
  • Gitee AI上线:开启免费DeepSeek模型新时代
  • 【论文复现】粘菌算法在最优经济排放调度中的发展与应用
  • libdrm移植到arm设备
  • PostgreSQL证书什么样子的?
  • Android studio:顶部导航栏Toolbar