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

devtools/2025/2/7 23:43:22/

目录

概述

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.ppmy.cn/devtools/156961.html

相关文章

MySQL系列之数据类型(DateTime)

导览 前言一、日期/时间类型 1. Date 1.1 取值范围1.2 显示格式 2. Datetime 2.1 取值范围2.2 显示格式 3. Timestamp 3.1 取值范围3.2 显示格式 4. time 4.1 取值范围4.2 显示格式 5. year 5.1 取值范围5.2 显示格式 二、自动填充机制 1. 原理介绍2. 实现方式 2.1 案例12.2 …

PHP-三目运算(练习1)

[题目信息]&#xff1a; 题目名称题目难度PHP-三目运算(练习1)2 [题目考点]&#xff1a; PHP三目运算[Flag格式]: SangFor{Php_speciALHHH}[环境部署]&#xff1a; docker-compose.yml文件或者docker tar原始文件。 http://分配ip:2028[题目writeup]&#xff1a; 1、实验…

设计模式 ->模板方法模式(Template Method Pattern)

模板方法模式 模板方法模式是一种行为设计模式&#xff0c;它在一个方法中定义一个操作的算法骨架&#xff0c;而将一些步骤延迟到子类中实现。它允许子类在不改变算法结构的情况下重新定义算法中的某些步骤 特点 算法骨架&#xff1a; 在基类中定义算法的框架延迟实现&…

C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿、推荐…

网络安全—DDoS攻防

背景简述&#xff1a;DDoS攻击分为很多类型&#xff0c;有消耗网络带宽的流量攻击&#xff0c;有消耗服务器资源的应用层攻击等。影响巨大&#xff0c;且让无论大公司还是小公司都肃然“起敬”的当属&#xff1a;流量攻击。在流量越来越廉价的今天&#xff0c;攻击流量小则几百…

JavaScript前后端交互-AJAX/fetch

摘自千峰教育kerwin的js教程 AJAX 1、AJAX 的优势 不需要插件的支持&#xff0c;原生 js 就可以使用用户体验好&#xff08;不需要刷新页面就可以更新数据&#xff09;减轻服务端和带宽的负担缺点&#xff1a; 搜索引擎的支持度不够&#xff0c;因为数据都不在页面上&#xf…

【hot100】刷题记录(8)-矩阵置零

题目描述&#xff1a; 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例 2…

国产之光DeepSeek架构理解与应用分析

目录 初步探索DeepSeek的设计 一、核心架构设计 二、核心原理与优化 三、关键创新点 四、典型应用场景 五、与同类模型的对比优势 六、未来演进方向 从投入行业生产的角度看 一、DeepSeek的核心功能扩展 二、机械电子工程产业中的具体案例 1. 预测性维护&#xff08;Predictive…