今天更新:pthread linux 多线程编程的核心多线程库文件!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------2025.11.14
pthread.h到底是干啥的?怎么实现的? 全面详解
1. 头文件基础信息
c
/* Copyright (C) 2002-2024 Free Software Foundation, Inc. GNU C Library 的线程支持头文件 */ #ifndef _PTHREAD_H #define _PTHREAD_H 1
关键点:
-
这是 GNU C 库的一部分,遵循 LGPL 许可证
-
使用经典的头文件保护宏防止重复包含
-
#define _PTHREAD_H 1中的1是标识符,表示已定义
2. 包含的依赖头文件
c
#include <features.h> // 特性宏定义 #include <sched.h> // 调度相关 #include <time.h> // 时间处理 #include <bits/endian.h> // 字节序定义 #include <bits/pthreadtypes.h> // 线程类型定义 #include <bits/setjmp.h> // 跳转相关 // ... 其他架构相关头文件
3. 核心数据类型和枚举定义
3.1 线程分离状态
c
enum {
PTHREAD_CREATE_JOINABLE, // 可连接线程(默认)
PTHREAD_CREATE_DETACHED // 分离线程
};
实际应用对比:
| 状态 | 资源回收 | 能否获取返回值 | 使用场景 |
|---|---|---|---|
| JOINABLE | 需手动pthread_join | 可以 | 需要线程执行结果的场景 |
| DETACHED | 自动回收 | 不可以 | 后台任务、守护线程 |
3.2 互斥锁类型
c
enum {
PTHREAD_MUTEX_TIMED_NP, // 普通锁(默认)
PTHREAD_MUTEX_RECURSIVE_NP, // 递归锁
PTHREAD_MUTEX_ERRORCHECK_NP, // 错误检查锁
PTHREAD_MUTEX_ADAPTIVE_NP // 自适应锁
};
锁类型详解表格:
| 锁类型 | 重入性 | 错误检查 | 性能 | 适用场景 |
|---|---|---|---|---|
| NORMAL | 不可重入 | 无检查 | 最高 | 简单同步 |
| RECURSIVE | 可重入 | 有检查 | 较低 | 递归函数 |
| ERRORCHECK | 不可重入 | 有检查 | 中等 | 调试开发 |
| ADAPTIVE | 不可重入 | 无检查 | 自适应 | 高竞争场景 |
4. 核心函数分类解析
4.1 线程生命周期管理
创建线程:
c
int pthread_create(pthread_t *__newthread,
const pthread_attr_t *__attr,
void *(*__start_routine) (void *),
void *__restrict __arg);
代码示例:
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// 线程函数
void* thread_function(void* arg) {
int thread_num = *(int*)arg;
printf("线程 %d 正在运行\n", thread_num);
return NULL;
}
int main() {
pthread_t threads[3];
int thread_args[3] = {1, 2, 3};
// 创建3个线程
for (int i = 0; i < 3; i++) {
if (pthread_create(&threads[i], NULL, thread_function, &thread_args[i]) != 0) {
perror("pthread_create failed");
exit(1);
}
}
// 等待所有线程完成
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
printf("所有线程执行完毕\n");
return 0;
}
线程终止:
c
void pthread_exit(void *__retval); // 线程自行退出 int pthread_join(pthread_t __th, void **__thread_return); // 等待线程结束 int pthread_detach(pthread_t __th); // 分离线程
4.2 互斥锁操作详解
基础使用模式:
c
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int shared_data = 0;
void* increment_thread(void* arg) {
for (int i = 0; i < 100000; i++) {
pthread_mutex_lock(&mutex);
shared_data++;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, increment_thread, NULL);
pthread_create(&t2, NULL, increment_thread, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("最终结果: %d (期望: 200000)\n", shared_data);
return 0;
}
高级锁操作:
c
// 带超时的锁获取
int pthread_mutex_timedlock(pthread_mutex_t *__mutex,
const struct timespec *__abstime);
// 带时钟的锁获取
int pthread_mutex_clocklock(pthread_mutex_t *__mutex,
clockid_t __clockid,
const struct timespec *__abstime);
4.3 条件变量深度解析
生产者-消费者模式示例:
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#define BUFFER_SIZE 10
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_producer = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_consumer = PTHREAD_COND_INITIALIZER;
int buffer[BUFFER_SIZE];
int count = 0; // 缓冲区中元素数量
void* producer(void* arg) {
int item = 0;
while (1) {
pthread_mutex_lock(&mutex);
// 缓冲区满,等待消费者消费
while (count == BUFFER_SIZE) {
pthread_cond_wait(&cond_producer, &mutex);
}
// 生产项目
buffer[count] = item++;
count++;
printf("生产者生产: %d, 缓冲区大小: %d\n", item, count);
// 通知消费者
pthread_cond_signal(&cond_consumer);
pthread_mutex_unlock(&mutex);
usleep(100000); // 100ms
}
return NULL;
}
void* consumer(void* arg) {
while (1) {
pthread_mutex_lock(&mutex);
// 缓冲区空,等待生产者生产
while (count == 0) {
pthread_cond_wait(&cond_consumer, &mutex);
}
// 消费项目
int item = buffer[count - 1];
count--;
printf("消费者消费: %d, 缓冲区大小: %d\n", item, count);
// 通知生产者
pthread_cond_signal(&cond_producer);
pthread_mutex_unlock(&mutex);
usleep(150000); // 150ms
}
return NULL;
}
5. 线程属性设置详解
完整属性设置示例:
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void* demo_thread(void* arg) {
printf("自定义属性线程运行中...\n");
return NULL;
}
int main() {
pthread_t thread;
pthread_attr_t attr;
// 1. 初始化属性对象
if (pthread_attr_init(&attr) != 0) {
perror("pthread_attr_init");
exit(1);
}
// 2. 设置分离状态
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) != 0) {
perror("pthread_attr_setdetachstate");
exit(1);
}
// 3. 设置栈大小 (1MB)
size_t stack_size = 1024 * 1024;
if (pthread_attr_setstacksize(&attr, stack_size) != 0) {
perror("pthread_attr_setstacksize");
exit(1);
}
// 4. 设置调度策略
if (pthread_attr_setschedpolicy(&attr, SCHED_OTHER) != 0) {
perror("pthread_attr_setschedpolicy");
exit(1);
}
// 5. 创建线程
if (pthread_create(&thread, &attr, demo_thread, NULL) != 0) {
perror("pthread_create");
exit(1);
}
// 6. 销毁属性对象
pthread_attr_destroy(&attr);
// 7. 等待线程结束
pthread_join(thread, NULL);
printf("线程执行完成\n");
return 0;
}
6. 高级特性解析
6.1 线程取消机制
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 清理处理函数
void cleanup_handler(void* arg) {
printf("清理资源: %s\n", (char*)arg);
}
void* cancellable_thread(void* arg) {
// 注册清理处理程序
pthread_cleanup_push(cleanup_handler, "线程取消时的清理");
// 启用取消
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
printf("线程开始运行,5秒后将被取消\n");
for (int i = 0; i < 5; i++) {
printf("运行中... %d\n", i + 1);
sleep(1);
pthread_testcancel(); // 取消点
}
pthread_cleanup_pop(0); // 不执行清理(正常退出)
return NULL;
}
int main() {
pthread_t thread;
pthread_create(&thread, NULL, cancellable_thread, NULL);
sleep(3); // 等待3秒
printf("主线程取消工作线程\n");
pthread_cancel(thread);
pthread_join(thread, NULL);
printf("工作线程已被取消\n");
return 0;
}
6.2 线程局部存储 (TLS)
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// 创建线程特定数据键
pthread_key_t thread_log_key;
// 析构函数
void close_thread_log(void* thread_log) {
fclose((FILE*)thread_log);
printf("线程日志文件已关闭\n");
}
void* worker_thread(void* arg) {
int thread_id = *(int*)arg;
// 为每个线程创建独立的日志文件
char filename[100];
sprintf(filename, "thread_%d.log", thread_id);
FILE* thread_log = fopen(filename, "w");
if (thread_log != NULL) {
// 设置线程特定数据
pthread_setspecific(thread_log_key, thread_log);
fprintf(thread_log, "线程 %d 开始工作\n", thread_id);
}
// 获取线程特定数据并使用
FILE* log = pthread_getspecific(thread_log_key);
if (log != NULL) {
fprintf(log, "线程 %d 正在处理数据...\n", thread_id);
}
return NULL;
}
int main() {
pthread_t threads[3];
int thread_ids[3] = {1, 2, 3};
// 创建线程特定数据键
pthread_key_create(&thread_log_key, close_thread_log);
// 创建工作线程
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, worker_thread, &thread_ids[i]);
}
// 等待所有线程完成
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
// 销毁键
pthread_key_delete(thread_log_key);
printf("所有线程执行完毕\n");
return 0;
}
7. 同步原语对比分析
| 同步机制 | 适用场景 | 优点 | 缺点 | 性能 |
|---|---|---|---|---|
| 互斥锁 | 保护临界区 | 简单可靠 | 可能死锁 | 高 |
| 读写锁 | 读多写少 | 并发读 | 实现复杂 | 中高 |
| 条件变量 | 线程间通信 | 高效等待 | 需配合互斥锁 | 高 |
| 自旋锁 | 短临界区 | 无上下文切换 | 忙等待消耗CPU | 极高 |
| 屏障 | 多阶段计算 | 同步点控制 | 灵活性差 | 中 |
8. 错误处理最佳实践
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define CHECK_PTHREAD_CALL(call, msg) \
do { \
int result = (call); \
if (result != 0) { \
errno = result; \
perror(msg); \
exit(EXIT_FAILURE); \
} \
} while(0)
void* safe_thread(void* arg) {
printf("安全线程运行\n");
return NULL;
}
int main() {
pthread_t thread;
pthread_attr_t attr;
// 使用宏进行错误检查
CHECK_PTHREAD_CALL(pthread_attr_init(&attr), "pthread_attr_init");
CHECK_PTHREAD_CALL(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE),
"pthread_attr_setdetachstate");
CHECK_PTHREAD_CALL(pthread_create(&thread, &attr, safe_thread, NULL),
"pthread_create");
CHECK_PTHREAD_CALL(pthread_join(thread, NULL), "pthread_join");
CHECK_PTHREAD_CALL(pthread_attr_destroy(&attr), "pthread_attr_destroy");
printf("所有操作成功完成\n");
return 0;
}
9. 性能优化技巧
9.1 避免锁竞争的技巧
c
#include <pthread.h>
#include <stdio.h>
// 细粒度锁 - 每个数据结构独立的锁
typedef struct {
pthread_mutex_t lock;
int data;
} protected_int;
// 锁分层 - 避免死锁的固定加锁顺序
void safe_operation(protected_int *a, protected_int *b) {
// 总是先锁地址小的那个
if (a < b) {
pthread_mutex_lock(&a->lock);
pthread_mutex_lock(&b->lock);
} else {
pthread_mutex_lock(&b->lock);
pthread_mutex_lock(&a->lock);
}
// 执行操作
a->data += b->data;
// 解锁顺序与加锁顺序相反
pthread_mutex_unlock(&b->lock);
pthread_mutex_unlock(&a->lock);
}
10. 编译和链接
编译命令:
bash
# 编译多线程程序 gcc -pthread program.c -o program # 或者传统方式 gcc -lpthread program.c -o program
关键编译标志:
-
-pthread: 定义必要的宏并链接线程库 -
-D_REENTRANT: 定义可重入宏(现代编译器自动处理)
总结
pthread.h 提供了完整的 POSIX 线程编程接口,包括:
-
线程管理 - 创建、终止、连接、分离
-
同步机制 - 互斥锁、条件变量、读写锁、屏障
-
线程安全 - 线程特定数据、取消机制
-
性能控制 - 属性设置、调度控制
掌握这些 API 对于开发高性能、并发安全的应用程序至关重要。在实际使用中,要注意正确的错误处理和资源管理,避免常见的多线程陷阱如死锁、竞态条件等。
深入解析pthread.h:Linux多线程编程完全指南(第二部分)
第五章:线程同步原语深度剖析
5.1 互斥锁的高级特性与实现原理
5.1.1 互斥锁的内存布局与内核实现
在Linux系统中,互斥锁的实现经历了从用户态到内核态的演进。让我们深入分析其内部结构:
c
// pthreadtypes.h 中互斥锁的典型定义
typedef union {
struct __pthread_mutex_s {
int __lock; // 锁状态
unsigned int __count; // 递归计数
int __owner; // 当前持有者线程ID
unsigned int __nusers; // 用户计数
int __kind; // 锁类型
int __spins; // 自旋计数(自适应锁)
} __data;
char __size[__SIZEOF_PTHREAD_MUTEX_T]; // 总大小
long __align; // 对齐
} pthread_mutex_t;
互斥锁状态转换图:
text
锁状态机:
┌───────────┐ pthread_mutex_lock() ┌───────────┐
│ 未锁定 │ ────────────────────────> │ 已锁定 │
└───────────┘ └───────────┘
^ │
│ pthread_mutex_unlock() │
└──────────────────────────────────────┘
锁竞争处理策略对比表:
| 竞争处理策略 | 实现机制 | 适用场景 | 性能特点 |
|---|---|---|---|
| 直接阻塞 | 线程进入睡眠等待队列 | 锁持有时间长 | 上下文切换开销大 |
| 自旋等待 | 循环检查锁状态 | 锁持有时间短 | CPU占用高,响应快 |
| 适应性锁 | 先自旋后阻塞 | 中等持有时间 | 平衡性能 |
| 队列锁 | FIFO等待队列 | 公平性要求高 | 避免饥饿 |
5.1.2 递归锁的实现原理与应用场景
递归锁(Recursive Mutex)允许同一个线程多次获取同一个锁而不会死锁。这在递归函数或可重入代码中非常有用。
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 递归函数示例
void recursive_function(int depth, pthread_mutex_t *mutex) {
if (depth <= 0) return;
printf("深度 %d: 尝试获取锁...\n", depth);
pthread_mutex_lock(mutex);
printf("深度 %d: 成功获取锁\n", depth);
// 模拟工作
usleep(100000);
// 递归调用
recursive_function(depth - 1, mutex);
printf("深度 %d: 释放锁\n", depth);
pthread_mutex_unlock(mutex);
}
int main() {
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
// 设置递归锁属性
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
// 初始化递归锁
pthread_mutex_init(&mutex, &attr);
printf("开始递归锁测试...\n");
recursive_function(3, &mutex);
printf("递归锁测试完成\n");
// 清理资源
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&attr);
return 0;
}
递归锁内部计数机制:
c
// 伪代码:递归锁实现原理
struct recursive_mutex {
pthread_t owner; // 当前持有者
int count; // 递归计数
pthread_mutex_t internal_lock; // 内部保护锁
};
void recursive_lock(struct recursive_mutex *rmutex) {
pthread_t self = pthread_self();
pthread_mutex_lock(&rmutex->internal_lock);
if (rmutex->count > 0 && pthread_equal(rmutex->owner, self)) {
// 同一个线程重复获取锁
rmutex->count++;
} else {
// 等待真正的锁获取
while (rmutex->count > 0) {
pthread_mutex_unlock(&rmutex->internal_lock);
usleep(1000); // 短暂等待
pthread_mutex_lock(&rmutex->internal_lock);
}
rmutex->owner = self;
rmutex->count = 1;
}
pthread_mutex_unlock(&rmutex->internal_lock);
}
void recursive_unlock(struct recursive_mutex *rmutex) {
pthread_mutex_lock(&rmutex->internal_lock);
if (rmutex->count > 0 && pthread_equal(rmutex->owner, pthread_self())) {
rmutex->count--;
if (rmutex->count == 0) {
rmutex->owner = 0; // 清除所有者
}
}
pthread_mutex_unlock(&rmutex->internal_lock);
}
5.1.3 错误检查锁的实际应用
错误检查锁(Error-checking Mutex)能够在开发阶段帮助发现锁使用错误。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define CHECK(expr, msg) \
do { \
int ret = (expr); \
if (ret != 0) { \
fprintf(stderr, "%s: %s\n", msg, strerror(ret)); \
exit(EXIT_FAILURE); \
} \
} while(0)
void demonstrate_error_checking() {
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
// 创建错误检查锁
CHECK(pthread_mutexattr_init(&attr), "初始化属性失败");
CHECK(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK),
"设置错误检查类型失败");
CHECK(pthread_mutex_init(&mutex, &attr), "初始化互斥锁失败");
// 正确的使用方式
printf("测试1: 正常加锁解锁...\n");
CHECK(pthread_mutex_lock(&mutex), "加锁失败");
CHECK(pthread_mutex_unlock(&mutex), "解锁失败");
// 检测重复解锁错误
printf("测试2: 检测重复解锁错误...\n");
CHECK(pthread_mutex_lock(&mutex), "加锁失败");
CHECK(pthread_mutex_unlock(&mutex), "第一次解锁失败");
// 这里会产生错误:重复解锁
int result = pthread_mutex_unlock(&mutex);
if (result != 0) {
printf("检测到错误: 重复解锁 (%s)\n", strerror(result));
}
// 检测未持有锁时解锁的错误
printf("测试3: 检测未持有锁时解锁...\n");
result = pthread_mutex_unlock(&mutex);
if (result != 0) {
printf("检测到错误: 未持有锁时解锁 (%s)\n", strerror(result));
}
// 清理资源
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&attr);
}
int main() {
printf("错误检查锁演示开始\n");
demonstrate_error_checking();
printf("错误检查锁演示结束\n");
return 0;
}
5.2 条件变量的高级用法与性能优化
5.2.1 条件变量的内部实现机制
条件变量的实现依赖于内核的futex(快速用户空间互斥锁)机制,让我们深入了解其工作原理:
c
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
// 条件变量的内部状态模拟
struct condition_internal {
pthread_mutex_t *mutex; // 关联的互斥锁
int waiters; // 等待线程数
int signals; // 信号计数
struct timespec timeout; // 超时时间
};
void condition_variable_analysis() {
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
printf("条件变量大小: %zu 字节\n", sizeof(cond));
printf("互斥锁大小: %zu 字节\n", sizeof(mutex));
// 分析条件变量的内存布局
unsigned char *cond_bytes = (unsigned char*)&cond;
printf("条件变量内存布局: ");
for (size_t i = 0; i < sizeof(cond); i++) {
printf("%02x ", cond_bytes[i]);
}
printf("\n");
}
条件变量状态转换图:
text
条件变量状态机:
┌─────────────┐ pthread_cond_wait() ┌─────────────┐
│ 无等待 │ ───────────────────────> │ 等待中 │
└─────────────┘ └─────────────┘
^ │
│ pthread_cond_signal()/ │ pthread_cond_broadcast()
│ pthread_cond_broadcast() │
└──────────────────────────────────────┘
5.2.2 条件变量的超时与时钟选择
现代系统支持多种时钟源的条件变量等待,这在实时系统中尤为重要。
c
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
// 获取不同时钟的当前时间
void get_timespec(clockid_t clock_id, struct timespec *ts) {
if (clock_gettime(clock_id, ts) != 0) {
perror("clock_gettime");
ts->tv_sec = 0;
ts->tv_nsec = 0;
}
}
// 添加时间偏移
void add_timespec(struct timespec *ts, long seconds, long nanoseconds) {
ts->tv_sec += seconds;
ts->tv_nsec += nanoseconds;
if (ts->tv_nsec >= 1000000000L) {
ts->tv_sec += ts->tv_nsec / 1000000000L;
ts->tv_nsec %= 1000000000L;
}
}
void demonstrate_condition_timeouts() {
pthread_cond_t cond;
pthread_mutex_t mutex;
pthread_condattr_t cond_attr;
pthread_condattr_init(&cond_attr);
pthread_mutex_init(&mutex, NULL);
// 设置使用单调时钟(不受系统时间调整影响)
#ifdef _POSIX_CLOCK_SELECTION
pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
#endif
pthread_cond_init(&cond, &cond_attr);
pthread_mutex_lock(&mutex);
struct timespec timeout;
// 使用相对超时(3秒后)
#ifdef _POSIX_CLOCK_SELECTION
get_timespec(CLOCK_MONOTONIC, &timeout);
#else
get_timespec(CLOCK_REALTIME, &timeout);
#endif
add_timespec(&timeout, 3, 0); // 3秒超时
printf("开始条件变量等待,超时时间: %ld秒\n", timeout.tv_sec);
int result;
#ifdef _POSIX_CLOCK_SELECTION
result = pthread_cond_clockwait(&cond, &mutex, CLOCK_MONOTONIC, &timeout);
#else
result = pthread_cond_timedwait(&cond, &mutex, &timeout);
#endif
if (result == ETIMEDOUT) {
printf("条件变量等待超时\n");
} else if (result == 0) {
printf("条件变量被唤醒\n");
} else {
printf("条件变量等待错误: %s\n", strerror(result));
}
pthread_mutex_unlock(&mutex);
// 清理资源
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
pthread_condattr_destroy(&cond_attr);
}
int main() {
printf("条件变量超时演示开始\n");
demonstrate_condition_timeouts();
printf("条件变量超时演示结束\n");
return 0;
}
5.2.3 条件变量的虚假唤醒与处理策略
虚假唤醒(Spurious Wakeup)是条件变量编程中必须处理的重要问题。
c
#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>
// 线程安全的条件变量包装器
typedef struct {
pthread_cond_t cond;
pthread_mutex_t mutex;
bool condition_met;
int waiters;
} safe_condition_t;
void safe_condition_init(safe_condition_t *sc) {
pthread_cond_init(&sc->cond, NULL);
pthread_mutex_init(&sc->mutex, NULL);
sc->condition_met = false;
sc->waiters = 0;
}
void safe_condition_wait(safe_condition_t *sc, bool (*condition_check)(void*), void *arg) {
pthread_mutex_lock(&sc->mutex);
sc->waiters++;
// 必须使用while循环检查条件,防止虚假唤醒
while (!condition_check(arg) && !sc->condition_met) {
printf("线程 %lu: 进入等待,当前等待者: %d\n",
(unsigned long)pthread_self(), sc->waiters);
pthread_cond_wait(&sc->cond, &sc->mutex);
printf("线程 %lu: 被唤醒,重新检查条件\n",
(unsigned long)pthread_self());
}
sc->waiters--;
pthread_mutex_unlock(&sc->mutex);
}
void safe_condition_signal(safe_condition_t *sc) {
pthread_mutex_lock(&sc->mutex);
sc->condition_met = true;
printf("发送信号,唤醒一个等待者\n");
pthread_cond_signal(&sc->cond);
pthread_mutex_unlock(&sc->mutex);
}
void safe_condition_broadcast(safe_condition_t *sc) {
pthread_mutex_lock(&sc->mutex);
sc->condition_met = true;
printf("广播信号,唤醒所有等待者 (%d个)\n", sc->waiters);
pthread_cond_broadcast(&sc->cond);
pthread_mutex_unlock(&sc->mutex);
}
// 示例条件检查函数
bool global_condition_check(void *arg) {
int *value = (int*)arg;
return (*value >= 10);
}
// 测试线程函数
void* test_thread(void *arg) {
safe_condition_t *sc = (safe_condition_t*)arg;
static int counter = 0;
safe_condition_wait(sc, global_condition_check, &counter);
printf("线程 %lu: 条件满足,继续执行\n", (unsigned long)pthread_self());
return NULL;
}
int main() {
safe_condition_t sc;
safe_condition_init(&sc);
pthread_t threads[3];
printf("创建3个测试线程...\n");
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, test_thread, &sc);
}
// 模拟一些工作
sleep(2);
printf("主线程: 发送广播信号\n");
safe_condition_broadcast(&sc);
// 等待所有线程完成
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
printf("所有线程完成\n");
return 0;
}
5.3 读写锁的深入分析与性能优化
5.3.1 读写锁的内部实现机制
读写锁(Read-Write Lock)允许多个读操作并发执行,但写操作需要独占访问。
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 读写锁状态分析
void analyze_rwlock_state(pthread_rwlock_t *rwlock) {
// 注意:这只是一个演示,实际实现可能不同
printf("读写锁大小: %zu 字节\n", sizeof(*rwlock));
// 尝试获取读锁来分析状态
int result = pthread_rwlock_tryrdlock(rwlock);
if (result == 0) {
printf("状态: 可以获取读锁(无写锁持有)\n");
pthread_rwlock_unlock(rwlock);
} else if (result == EBUSY) {
printf("状态: 有写锁持有或写锁等待\n");
}
result = pthread_rwlock_trywrlock(rwlock);
if (result == 0) {
printf("状态: 可以获取写锁(完全空闲)\n");
pthread_rwlock_unlock(rwlock);
} else if (result == EBUSY) {
printf("状态: 有读锁或写锁持有\n");
}
}
// 读写锁性能测试
void* reader_thread(void *arg) {
pthread_rwlock_t *rwlock = (pthread_rwlock_t*)arg;
int reads_completed = 0;
for (int i = 0; i < 1000; i++) {
pthread_rwlock_rdlock(rwlock);
// 模拟读操作
usleep(100); // 100微秒
pthread_rwlock_unlock(rwlock);
reads_completed++;
}
printf("读线程 %lu: 完成 %d 次读操作\n",
(unsigned long)pthread_self(), reads_completed);
return NULL;
}
void* writer_thread(void *arg) {
pthread_rwlock_t *rwlock = (pthread_rwlock_t*)arg;
int writes_completed = 0;
for (int i = 0; i < 100; i++) {
pthread_rwlock_wrlock(rwlock);
// 模拟写操作
usleep(1000); // 1毫秒
pthread_rwlock_unlock(rwlock);
writes_completed++;
}
printf("写线程 %lu: 完成 %d 次写操作\n",
(unsigned long)pthread_self(), writes_completed);
return NULL;
}
void performance_test() {
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
pthread_t readers[5], writers[2];
printf("开始读写锁性能测试...\n");
// 创建读线程
for (int i = 0; i < 5; i++) {
pthread_create(&readers[i], NULL, reader_thread, &rwlock);
}
// 创建写线程
for (int i = 0; i < 2; i++) {
pthread_create(&writers[i], NULL, writer_thread, &rwlock);
}
// 等待所有线程完成
for (int i = 0; i < 5; i++) {
pthread_join(readers[i], NULL);
}
for (int i = 0; i < 2; i++) {
pthread_join(writers[i], NULL);
}
pthread_rwlock_destroy(&rwlock);
printf("性能测试完成\n");
}
int main() {
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
printf("=== 读写锁分析 ===\n");
analyze_rwlock_state(&rwlock);
printf("\n=== 性能测试 ===\n");
performance_test();
pthread_rwlock_destroy(&rwlock);
return 0;
}
5.3.2 读写锁的优先级策略
不同的读写锁实现支持不同的优先级策略,影响读线程和写线程的调度。
c
#include <pthread.h>
#include <stdio.h>
void demonstrate_rwlock_preferences() {
pthread_rwlock_t rwlock;
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
// 测试不同的优先级策略
int preferences[] = {
PTHREAD_RWLOCK_PREFER_READER_NP, // 偏向读者
PTHREAD_RWLOCK_PREFER_WRITER_NP, // 偏向写者
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP // 偏向非递归写者
};
const char *preference_names[] = {
"读者优先",
"写者优先",
"非递归写者优先"
};
for (int i = 0; i < 3; i++) {
printf("\n=== 测试策略: %s ===\n", preference_names[i]);
pthread_rwlockattr_setkind_np(&attr, preferences[i]);
pthread_rwlock_init(&rwlock, &attr);
// 获取当前设置的策略
int current_pref;
pthread_rwlockattr_getkind_np(&attr, ¤t_pref);
printf("当前策略代码: %d\n", current_pref);
pthread_rwlock_destroy(&rwlock);
}
pthread_rwlockattr_destroy(&attr);
}
// 读者优先 vs 写者优先的性能影响分析
void analyze_preference_impact() {
printf("\n=== 优先级策略性能影响分析 ===\n");
printf("1. 读者优先 (PTHREAD_RWLOCK_PREFER_READER_NP):\n");
printf(" - 优点: 读吞吐量高\n");
printf(" - 缺点: 写者可能饥饿\n");
printf(" - 适用: 读多写少的场景\n\n");
printf("2. 写者优先 (PTHREAD_RWLOCK_PREFER_WRITER_NP):\n");
printf(" - 优点: 写操作响应快\n");
printf(" - 缺点: 读者可能饥饿\n");
printf(" - 适用: 写操作重要的场景\n\n");
printf("3. 非递归写者优先 (PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP):\n");
printf(" - 优点: 避免写者饥饿的公平策略\n");
printf(" - 缺点: 实现复杂度高\n");
printf(" - 适用: 需要公平性的场景\n");
}
int main() {
demonstrate_rwlock_preferences();
analyze_preference_impact();
return 0;
}
5.4 自旋锁与适应性互斥锁
5.4.1 自旋锁的实现与适用场景
自旋锁(Spinlock)在短时间内避免上下文切换,适用于多核系统中的短临界区保护。
c
#include <pthread.h>
#include <stdio.h>
#include <sched.h>
// 自定义自旋锁实现(教育目的)
typedef struct {
volatile int lock;
} custom_spinlock_t;
void custom_spin_init(custom_spinlock_t *spinlock) {
spinlock->lock = 0;
}
void custom_spin_lock(custom_spinlock_t *spinlock) {
while (__sync_lock_test_and_set(&spinlock->lock, 1)) {
// 自旋等待,但要让出CPU避免过度占用
while (spinlock->lock) {
// 使用CPU暂停指令减少功耗(如果可用)
#ifdef __x86_64__
asm volatile("pause" ::: "memory");
#endif
// 短暂让出CPU
sched_yield();
}
}
}
void custom_spin_unlock(custom_spinlock_t *spinlock) {
__sync_lock_release(&spinlock->lock);
}
// 性能对比:自旋锁 vs 互斥锁
#include <time.h>
void benchmark_spinlock_vs_mutex() {
const int ITERATIONS = 1000000;
struct timespec start, end;
// 测试自旋锁
pthread_spinlock_t spinlock;
pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < ITERATIONS; i++) {
pthread_spin_lock(&spinlock);
// 极短临界区
pthread_spin_unlock(&spinlock);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long spin_time = (end.tv_sec - start.tv_sec) * 1000000000L +
(end.tv_nsec - start.tv_nsec);
// 测试互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < ITERATIONS; i++) {
pthread_mutex_lock(&mutex);
// 极短临界区
pthread_mutex_unlock(&mutex);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long mutex_time = (end.tv_sec - start.tv_sec) * 1000000000L +
(end.tv_nsec - start.tv_nsec);
printf("性能对比结果:\n");
printf("自旋锁: %ld 纳秒 (%d 次操作)\n", spin_time, ITERATIONS);
printf("互斥锁: %ld 纳秒 (%d 次操作)\n", mutex_time, ITERATIONS);
printf("自旋锁/互斥锁时间比: %.2f\n", (double)spin_time / mutex_time);
pthread_spin_destroy(&spinlock);
pthread_mutex_destroy(&mutex);
}
int main() {
printf("=== 自旋锁演示 ===\n");
custom_spinlock_t spinlock;
custom_spin_init(&spinlock);
printf("自定义自旋锁测试...\n");
custom_spin_lock(&spinlock);
printf("自旋锁已获取\n");
custom_spin_unlock(&spinlock);
printf("自旋锁已释放\n");
printf("\n=== 性能对比测试 ===\n");
benchmark_spinlock_vs_mutex();
return 0;
}
5.4.2 适应性互斥锁的工作原理
适应性互斥锁(Adaptive Mutex)结合了自旋锁和传统互斥锁的优点,根据临界区长度动态选择策略。
c
#include <pthread.h>
#include <stdio.h>
#include <time.h>
// 适应性锁策略分析
void analyze_adaptive_behavior() {
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
pthread_mutex_init(&mutex, &attr);
printf("适应性互斥锁特性分析:\n");
printf("1. 短临界区: 采用自旋等待,避免上下文切换\n");
printf("2. 长临界区: 切换到阻塞等待,释放CPU\n");
printf("3. 自适应: 根据历史等待时间调整策略\n");
// 测试短临界区(预期使用自旋)
struct timespec short_start, short_end;
clock_gettime(CLOCK_MONOTONIC, &short_start);
for (int i = 0; i < 1000; i++) {
pthread_mutex_lock(&mutex);
// 极短工作 - 几个纳秒
pthread_mutex_unlock(&mutex);
}
clock_gettime(CLOCK_MONOTONIC, &short_end);
long short_time = (short_end.tv_sec - short_start.tv_sec) * 1000000000L +
(short_end.tv_nsec - short_start.tv_nsec);
// 测试长临界区(预期使用阻塞)
clock_gettime(CLOCK_MONOTONIC, &short_start);
for (int i = 0; i < 10; i++) {
pthread_mutex_lock(&mutex);
// 较长工作 - 1毫秒
struct timespec sleep_time = {0, 1000000}; // 1毫秒
nanosleep(&sleep_time, NULL);
pthread_mutex_unlock(&mutex);
}
clock_gettime(CLOCK_MONOTONIC, &short_end);
long long_time = (short_end.tv_sec - short_start.tv_sec) * 1000000000L +
(short_end.tv_nsec - short_start.tv_nsec);
printf("\n性能数据:\n");
printf("短临界区(1000次): %ld 纳秒\n", short_time);
printf("长临界区(10次): %ld 纳秒\n", long_time);
printf("平均每次短操作: %ld 纳秒\n", short_time / 1000);
printf("平均每次长操作: %ld 纳秒\n", long_time / 10);
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&attr);
}
// 适应性锁 vs 其他锁类型对比
void compare_mutex_types() {
printf("\n=== 互斥锁类型对比 ===\n");
int mutex_types[] = {
PTHREAD_MUTEX_NORMAL,
PTHREAD_MUTEX_RECURSIVE,
PTHREAD_MUTEX_ERRORCHECK,
PTHREAD_MUTEX_ADAPTIVE_NP
};
const char *type_names[] = {
"普通锁",
"递归锁",
"错误检查锁",
"适应性锁"
};
for (int i = 0; i < 4; i++) {
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, mutex_types[i]);
if (pthread_mutex_init(&mutex, &attr) == 0) {
printf("%s: 初始化成功\n", type_names[i]);
pthread_mutex_destroy(&mutex);
} else {
printf("%s: 初始化失败\n", type_names[i]);
}
pthread_mutexattr_destroy(&attr);
}
}
int main() {
printf("适应性互斥锁深入分析\n");
analyze_adaptive_behavior();
compare_mutex_types();
return 0;
}
第六章:线程安全与可重入编程
6.1 线程安全函数的设计原则
6.1.1 可重入函数与线程安全函数的区别
理解可重入(Reentrant)和线程安全(Thread-safe)的区别对于编写高质量的多线程代码至关重要。
c
#include <pthread.h>
#include <stdio.h>
#include <string.h>
// 非线程安全的函数示例
static char buffer[100];
char* unsafe_greeting(const char *name) {
// 使用静态缓冲区 - 非线程安全
snprintf(buffer, sizeof(buffer), "Hello, %s!", name);
return buffer;
}
// 线程安全的可重入版本
char* safe_greeting(const char *name, char *buffer, size_t size) {
// 使用调用者提供的缓冲区 - 线程安全且可重入
snprintf(buffer, size, "Hello, %s!", name);
return buffer;
}
// 测试函数
void* test_unsafe_thread(void *arg) {
int thread_id = *(int*)arg;
// 非线程安全版本的测试
char *result = unsafe_greeting("World");
printf("线程 %d: %s (地址: %p)\n", thread_id, result, (void*)result);
return NULL;
}
void* test_safe_thread(void *arg) {
int thread_id = *(int*)arg;
char local_buffer[100];
// 线程安全版本的测试
char *result = safe_greeting("World", local_buffer, sizeof(local_buffer));
printf("线程 %d: %s (地址: %p)\n", thread_id, result, (void*)result);
return NULL;
}
void demonstrate_safety_issues() {
pthread_t threads[3];
int thread_ids[3] = {1, 2, 3};
printf("=== 非线程安全函数测试 ===\n");
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, test_unsafe_thread, &thread_ids[i]);
}
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
printf("\n=== 线程安全函数测试 ===\n");
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, test_safe_thread, &thread_ids[i]);
}
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
}
// 可重入函数的设计模式
typedef struct {
int value;
pthread_mutex_t mutex;
} thread_safe_counter;
void counter_init(thread_safe_counter *counter) {
counter->value = 0;
pthread_mutex_init(&counter->mutex, NULL);
}
void counter_increment(thread_safe_counter *counter) {
pthread_mutex_lock(&counter->mutex);
counter->value++;
pthread_mutex_unlock(&counter->mutex);
}
int counter_get(thread_safe_counter *counter) {
pthread_mutex_lock(&counter->mutex);
int value = counter->value;
pthread_mutex_unlock(&counter->mutex);
return value;
}
void counter_destroy(thread_safe_counter *counter) {
pthread_mutex_destroy(&counter->mutex);
}
int main() {
printf("线程安全与可重入编程演示\n");
demonstrate_safety_issues();
// 线程安全计数器的使用示例
thread_safe_counter counter;
counter_init(&counter);
pthread_t threads[5];
for (int i = 0; i < 5; i++) {
pthread_create(&threads[i], NULL,
(void*(*)(void*))counter_increment, &counter);
}
for (int i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}
printf("最终计数值: %d\n", counter_get(&counter));
counter_destroy(&counter);
return 0;
}
6.1.2 线程局部存储的高级用法
线程局部存储(Thread-Local Storage, TLS)允许每个线程拥有变量的独立副本,是实现线程安全的重要工具。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// C11 线程局部存储关键字
_Thread_local int tls_var = 0;
// POSIX 线程特定数据
pthread_key_t tls_key;
void tls_destructor(void *value) {
printf("清理线程特定数据: %p\n", value);
free(value);
}
void init_tls() {
pthread_key_create(&tls_key, tls_destructor);
}
int* get_thread_specific_data() {
int *data = pthread_getspecific(tls_key);
if (data == NULL) {
data = malloc(sizeof(int));
*data = 0;
pthread_setspecific(tls_key, data);
printf("为线程 %lu 分配线程特定数据\n", (unsigned long)pthread_self());
}
return data;
}
void* tls_test_thread(void *arg) {
int thread_id = *(int*)arg;
// 使用 C11 _Thread_local
tls_var = thread_id * 10;
printf("线程 %d: C11 TLS 变量 = %d\n", thread_id, tls_var);
// 使用 POSIX 线程特定数据
int *data = get_thread_specific_data();
*data = thread_id * 100;
printf("线程 %d: POSIX TLS 数据 = %d\n", thread_id, *data);
return NULL;
}
void demonstrate_tls_performance() {
const int NUM_THREADS = 100;
const int NUM_ITERATIONS = 1000;
pthread_t threads[NUM_THREADS];
int thread_ids[NUM_THREADS];
init_tls();
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// 创建大量线程测试TLS性能
for (int i = 0; i < NUM_THREADS; i++) {
thread_ids[i] = i;
pthread_create(&threads[i], NULL, tls_test_thread, &thread_ids[i]);
}
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long time_taken = (end.tv_sec - start.tv_sec) * 1000000000L +
(end.tv_nsec - start.tv_nsec);
printf("TLS性能测试: %d个线程完成,总时间: %ld 纳秒\n",
NUM_THREADS, time_taken);
pthread_key_delete(tls_key);
}
// TLS在复杂数据结构中的应用
typedef struct {
int id;
char name[50];
double values[100];
} thread_context_t;
pthread_key_t context_key;
void context_destructor(void *value) {
thread_context_t *context = (thread_context_t*)value;
printf("清理线程上下文: %s (ID: %d)\n", context->name, context->id);
free(context);
}
void init_context_tls() {
pthread_key_create(&context_key, context_destructor);
}
thread_context_t* get_thread_context() {
thread_context_t *context = pthread_getspecific(context_key);
if (context == NULL) {
context = malloc(sizeof(thread_context_t));
context->id = (int)pthread_self() % 1000; // 简单ID生成
snprintf(context->name, sizeof(context->name), "Thread-%lu",
(unsigned long)pthread_self());
// 初始化数据
for (int i = 0; i < 100; i++) {
context->values[i] = (double)i * 1.5;
}
pthread_setspecific(context_key, context);
printf("创建线程上下文: %s\n", context->name);
}
return context;
}
void* complex_tls_thread(void *arg) {
thread_context_t *context = get_thread_context();
// 使用线程上下文
printf("线程 %s 开始工作,values[0] = %.2f\n",
context->name, context->values[0]);
// 修改上下文数据
for (int i = 0; i < 10; i++) {
context->values[i] *= 2.0;
}
printf("线程 %s 完成工作,values[0] = %.2f\n",
context->name, context->values[0]);
return NULL;
}
int main() {
printf("=== 线程局部存储高级用法演示 ===\n");
printf("\n1. 基础TLS性能测试:\n");
demonstrate_tls_performance();
printf("\n2. 复杂数据结构TLS应用:\n");
init_context_tls();
pthread_t threads[3];
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, complex_tls_thread, NULL);
}
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
pthread_key_delete(context_key);
return 0;
}
由于篇幅限制,先提供这两个章节的详细内容。这些内容涵盖了线程同步原语的高级特性和线程安全编程的核心!!!!
------------------------------------------------------------------------------------------------------------------2025.11.3晚跟新于笔记本
深入解析pthread.h:Linux多线程编程完全指南(第三部分)
第七章:线程取消机制与资源清理
7.1 线程取消的深入理解
7.1.1 取消点的详细分析
取消点是线程检查取消请求并可能终止的特殊位置。理解这些位置对于编写可靠的取消安全代码至关重要。
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
// 测试各种取消点的函数
void test_cancellation_points() {
printf("=== 取消点测试 ===\n");
// 1. 标准I/O函数 - 取消点
printf("测试标准I/O取消点...\n");
printf("这是一个潜在的取消点\n");
// 2. 文件I/O操作 - 取消点
printf("测试文件I/O取消点...\n");
int fd = open("/tmp/test_cancel", O_CREAT | O_RDWR, 0644);
if (fd >= 0) {
char buffer[100];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
printf("读取了 %zd 字节\n", bytes_read);
ssize_t bytes_written = write(fd, "test", 4);
printf("写入了 %zd 字节\n", bytes_written);
close(fd);
}
// 3. 进程控制 - 取消点
printf("测试进程控制取消点...\n");
pid_t pid = fork();
if (pid == 0) {
// 子进程
printf("子进程创建成功\n");
_exit(0);
} else if (pid > 0) {
// 父进程
waitpid(pid, NULL, 0);
}
// 4. 线程操作 - 取消点
printf("测试线程操作取消点...\n");
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
struct timespec timeout;
clock_gettime(CLOCK_REALTIME, &timeout);
timeout.tv_sec += 1; // 1秒超时
pthread_cond_timedwait(&cond, &mutex, &timeout);
pthread_mutex_unlock(&mutex);
printf("所有取消点测试完成\n");
}
// 手动取消点测试
void* cancellation_test_thread(void* arg) {
int thread_id = *(int*)arg;
printf("线程 %d: 开始执行\n", thread_id);
// 非取消点区域 - 不会被取消
for (int i = 0; i < 3; i++) {
printf("线程 %d: 计算中... %d\n", thread_id, i);
// 这里不是取消点,除非我们手动添加
}
// 手动添加取消点
printf("线程 %d: 添加手动取消点\n", thread_id);
pthread_testcancel();
// 取消点区域
printf("线程 %d: 进入取消点区域\n", thread_id);
sleep(2); // sleep是取消点
printf("线程 %d: 正常完成\n", thread_id);
return NULL;
}
void demonstrate_cancellation_points() {
pthread_t threads[3];
int thread_ids[3] = {1, 2, 3};
printf("创建3个测试线程...\n");
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, cancellation_test_thread, &thread_ids[i]);
}
// 给线程一些时间执行
usleep(500000); // 0.5秒
// 取消线程2
printf("取消线程2...\n");
pthread_cancel(threads[1]);
// 等待所有线程
for (int i = 0; i < 3; i++) {
void *result;
pthread_join(threads[i], &result);
if (result == PTHREAD_CANCELED) {
printf("线程 %d 被取消\n", i + 1);
} else {
printf("线程 %d 正常完成\n", i + 1);
}
}
}
int main() {
printf("线程取消机制深入分析\n");
// 测试各种取消点
test_cancellation_points();
printf("\n=== 取消点行为演示 ===\n");
demonstrate_cancellation_points();
return 0;
}
7.1.2 取消类型与状态的组合效应
线程取消的行为由取消状态和取消类型的组合决定,理解这些组合对于编写正确的取消安全代码至关重要。
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 取消状态和类型组合测试
typedef struct {
int state; // 取消状态
int type; // 取消类型
const char* name;
} cancel_config_t;
void* test_cancel_config(void* arg) {
cancel_config_t* config = (cancel_config_t*)arg;
int old_state, old_type;
printf("线程 %s: 设置取消状态=%s, 类型=%s\n",
config->name,
config->state == PTHREAD_CANCEL_ENABLE ? "启用" : "禁用",
config->type == PTHREAD_CANCEL_DEFERRED ? "延迟" : "异步");
// 设置取消状态和类型
pthread_setcancelstate(config->state, &old_state);
pthread_setcanceltype(config->type, &old_type);
printf("线程 %s: 旧状态=%s, 旧类型=%s\n",
config->name,
old_state == PTHREAD_CANCEL_ENABLE ? "启用" : "禁用",
old_type == PTHREAD_CANCEL_DEFERRED ? "延迟" : "异步");
// 执行一些工作
for (int i = 0; i < 5; i++) {
printf("线程 %s: 工作循环 %d\n", config->name, i);
if (i == 2) {
printf("线程 %s: 在循环中间\n", config->name);
// 手动取消点
pthread_testcancel();
}
usleep(200000); // 200ms
}
printf("线程 %s: 正常完成\n", config->name);
return (void*)(long)config->name[0]; // 返回第一个字符作为标识
}
void analyze_cancel_combinations() {
pthread_t threads[4];
cancel_config_t configs[4] = {
{PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DEFERRED, "启用-延迟"},
{PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_ASYNCHRONOUS, "启用-异步"},
{PTHREAD_CANCEL_DISABLE, PTHREAD_CANCEL_DEFERRED, "禁用-延迟"},
{PTHREAD_CANCEL_DISABLE, PTHREAD_CANCEL_ASYNCHRONOUS, "禁用-异步"}
};
printf("=== 取消配置组合分析 ===\n");
// 创建测试线程
for (int i = 0; i < 4; i++) {
pthread_create(&threads[i], NULL, test_cancel_config, &configs[i]);
}
// 给线程一些时间开始执行
sleep(1);
// 取消所有线程
printf("\n主线程: 取消所有测试线程\n");
for (int i = 0; i < 4; i++) {
pthread_cancel(threads[i]);
}
// 等待线程结束并分析结果
for (int i = 0; i < 4; i++) {
void* result;
pthread_join(threads[i], &result);
if (result == PTHREAD_CANCELED) {
printf("线程 %s: 被取消\n", configs[i].name);
} else {
printf("线程 %s: 正常完成 (结果: %ld)\n",
configs[i].name, (long)result);
}
}
printf("\n=== 取消配置行为总结 ===\n");
printf("1. 启用-延迟: 只在取消点响应取消\n");
printf("2. 启用-异步: 任何时间点都可能被取消\n");
printf("3. 禁用-延迟: 忽略取消请求\n");
printf("4. 禁用-异步: 忽略取消请求\n");
}
// 异步取消的安全考虑
void* async_cancel_unsafe(void* arg) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
// 危险操作:可能在malloc中间被取消
printf("异步取消线程: 分配内存...\n");
char* buffer = malloc(1024);
if (buffer) {
// 可能在这里被取消,导致内存泄漏
strcpy(buffer, "Hello, World!");
printf("异步取消线程: %s\n", buffer);
free(buffer); // 可能永远不会执行
}
return NULL;
}
void* async_cancel_safe(void* arg) {
// 在关键区域禁用取消
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
printf("安全异步取消线程: 分配内存...\n");
char* buffer = malloc(1024);
if (buffer) {
strcpy(buffer, "Hello, Safe World!");
printf("安全异步取消线程: %s\n", buffer);
}
// 重新启用取消
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
// 现在可以安全取消了
pthread_testcancel();
if (buffer) {
free(buffer); // 确保释放内存
}
return NULL;
}
int main() {
printf("取消类型与状态组合分析\n");
analyze_cancel_combinations();
printf("\n=== 异步取消安全性演示 ===\n");
pthread_t unsafe_thread, safe_thread;
printf("创建不安全异步取消线程...\n");
pthread_create(&unsafe_thread, NULL, async_cancel_unsafe, NULL);
usleep(100000);
pthread_cancel(unsafe_thread);
pthread_join(unsafe_thread, NULL);
printf("不安全线程结束(可能内存泄漏)\n");
printf("创建安全异步取消线程...\n");
pthread_create(&safe_thread, NULL, async_cancel_safe, NULL);
usleep(100000);
pthread_cancel(safe_thread);
pthread_join(safe_thread, NULL);
printf("安全线程结束(无内存泄漏)\n");
return 0;
}
7.2 清理处理程序的复杂应用
7.2.1 多级清理处理程序
在复杂的多线程应用中,可能需要多级清理处理程序来正确处理资源释放。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 资源类型定义
typedef struct {
int id;
char name[50];
void* data;
} resource_t;
// 多级清理处理程序
void cleanup_level3(void* arg) {
resource_t* res = (resource_t*)arg;
printf("三级清理: 释放资源数据 %s (ID: %d)\n", res->name, res->id);
if (res->data) {
free(res->data);
res->data = NULL;
}
}
void cleanup_level2(void* arg) {
resource_t* res = (resource_t*)arg;
printf("二级清理: 关闭资源 %s (ID: %d)\n", res->name, res->id);
// 注册三级清理
pthread_cleanup_push(cleanup_level3, res);
pthread_cleanup_pop(1); // 立即执行三级清理
}
void cleanup_level1(void* arg) {
resource_t* res = (resource_t*)arg;
printf("一级清理: 资源 %s (ID: %d) 开始清理\n", res->name, res->id);
// 注册二级清理
pthread_cleanup_push(cleanup_level2, res);
pthread_cleanup_pop(1); // 立即执行二级清理
}
// 复杂资源分配函数
resource_t* allocate_complex_resource(int id, const char* name) {
resource_t* res = malloc(sizeof(resource_t));
if (res) {
res->id = id;
snprintf(res->name, sizeof(res->name), "%s", name);
res->data = malloc(100); // 分配一些数据
if (res->data) {
snprintf((char*)res->data, 100, "数据内容 %s", name);
}
printf("分配资源: %s (ID: %d)\n", res->name, res->id);
}
return res;
}
void complex_operation(resource_t* res1, resource_t* res2) {
// 注册一级清理处理程序
pthread_cleanup_push(cleanup_level1, res1);
pthread_cleanup_push(cleanup_level1, res2);
printf("执行复杂操作...\n");
// 模拟一些工作
for (int i = 0; i < 3; i++) {
printf("操作步骤 %d\n", i);
usleep(500000);
// 在某个步骤模拟错误,触发清理
if (i == 1) {
printf("模拟操作失败,触发清理\n");
pthread_exit(NULL); // 这会触发清理处理程序
}
}
printf("操作成功完成\n");
// 正常完成,不执行清理(参数为0)
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
}
void* complex_worker_thread(void* arg) {
int thread_id = *(int*)arg;
printf("线程 %d: 开始复杂工作\n", thread_id);
// 分配多个资源
resource_t* res1 = allocate_complex_resource(thread_id * 10 + 1, "资源A");
resource_t* res2 = allocate_complex_resource(thread_id * 10 + 2, "资源B");
if (!res1 || !res2) {
printf("线程 %d: 资源分配失败\n", thread_id);
if (res1) free(res1);
if (res2) free(res2);
return NULL;
}
// 执行复杂操作(带有清理处理程序)
complex_operation(res1, res2);
// 如果正常完成,手动释放资源
printf("线程 %d: 手动释放资源\n", thread_id);
cleanup_level1(res1);
cleanup_level1(res2);
free(res1);
free(res2);
printf("线程 %d: 工作完成\n", thread_id);
return NULL;
}
int main() {
printf("=== 多级清理处理程序演示 ===\n");
pthread_t thread;
int thread_id = 1;
pthread_create(&thread, NULL, complex_worker_thread, &thread_id);
// 等待线程完成
pthread_join(thread, NULL);
printf("主线程: 复杂工作演示完成\n");
return 0;
}
7.2.2 清理处理程序的异常安全
清理处理程序提供了类似C++ RAII的异常安全保证,确保资源在任何退出路径上都能被正确释放。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
// 异常安全的文件操作包装器
typedef struct {
FILE* file;
const char* filename;
} file_handle_t;
void file_cleanup(void* arg) {
file_handle_t* fh = (file_handle_t*)arg;
if (fh && fh->file) {
printf("清理: 关闭文件 %s\n", fh->filename);
fclose(fh->file);
fh->file = NULL;
}
}
// 异常安全的文件打开
FILE* safe_fopen(const char* filename, const char* mode, file_handle_t* fh) {
fh->filename = filename;
fh->file = fopen(filename, mode);
if (fh->file) {
printf("成功打开文件: %s\n", filename);
// 注册清理处理程序
pthread_cleanup_push(file_cleanup, fh);
} else {
printf("无法打开文件: %s\n", filename);
}
return fh->file;
}
// 异常安全的文件操作函数
void process_file_safely(const char* filename) {
file_handle_t fh = {NULL, filename};
int cleanup_needed = 0;
// 使用清理处理程序确保资源释放
if (safe_fopen(filename, "w", &fh)) {
cleanup_needed = 1;
pthread_cleanup_push(file_cleanup, &fh);
printf("开始处理文件...\n");
// 模拟可能失败的操作
for (int i = 0; i < 5; i++) {
printf("处理步骤 %d\n", i);
// 在步骤2模拟失败
if (i == 2) {
printf("模拟操作失败!\n");
pthread_exit(NULL); // 触发清理
}
// 写入文件
fprintf(fh.file, "数据行 %d\n", i);
}
printf("文件处理成功完成\n");
pthread_cleanup_pop(0); // 正常完成,不执行清理
cleanup_needed = 0;
}
// 如果正常完成,手动关闭文件
if (!cleanup_needed && fh.file) {
fclose(fh.file);
}
}
// 基于setjmp/longjmp的异常处理与清理处理程序的结合
static jmp_buf env;
void cleanup_with_longjmp(void* arg) {
printf("在longjmp前执行清理: %s\n", (char*)arg);
}
void* exception_safe_thread(void* arg) {
char* resource1 = "资源1";
char* resource2 = "资源2";
// 设置异常处理
if (setjmp(env) == 0) {
// 第一次执行,注册清理处理程序
pthread_cleanup_push(cleanup_with_longjmp, resource1);
pthread_cleanup_push(cleanup_with_longjmp, resource2);
printf("线程: 正常执行路径\n");
// 模拟一些工作
for (int i = 0; i < 3; i++) {
printf("工作步骤 %d\n", i);
// 在步骤1模拟严重错误
if (i == 1) {
printf遇到严重错误,执行longjmp!\n");
longjmp(env, 1); // 跳转到setjmp位置
}
}
printf("线程: 正常完成\n");
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
} else {
// longjmp后的恢复路径
printf("线程: 从异常中恢复\n");
// 注意:longjmp不会触发清理处理程序!
// 我们需要手动调用或使用其他机制
cleanup_with_longjmp(resource1);
cleanup_with_longjmp(resource2);
}
return NULL;
}
int main() {
printf("=== 异常安全与清理处理程序 ===\n");
printf("\n1. 文件操作异常安全演示:\n");
pthread_t file_thread;
pthread_create(&file_thread, NULL,
(void*(*)(void*))process_file_safely, "test_file.txt");
pthread_join(file_thread, NULL);
printf("\n2. setjmp/longjmp与清理处理程序:\n");
pthread_t exception_thread;
pthread_create(&exception_thread, NULL, exception_safe_thread, NULL);
pthread_join(exception_thread, NULL);
printf("\n=== 重要注意事项 ===\n");
printf("1. pthread_exit() 会触发清理处理程序\n");
printf("2. longjmp() 不会触发清理处理程序\n");
printf("3. return 不会触发清理处理程序\n");
printf("4. 正常完成时应使用pthread_cleanup_pop(0)\n");
return 0;
}
第八章:多线程调试与问题诊断
8.1 死锁检测与预防
8.1.1 死锁的自动检测机制
通过包装锁操作来检测潜在的死锁情况。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
// 线程安全的死锁检测器
typedef struct {
pthread_mutex_t mutex;
pthread_t* lock_owners;
pthread_mutex_t** owned_locks;
int max_locks;
} deadlock_detector_t;
deadlock_detector_t* detector_create(int max_locks) {
deadlock_detector_t* detector = malloc(sizeof(deadlock_detector_t));
detector->max_locks = max_locks;
detector->lock_owners = calloc(max_locks, sizeof(pthread_t));
detector->owned_locks = calloc(max_locks, sizeof(pthread_mutex_t*));
pthread_mutex_init(&detector->mutex, NULL);
return detector;
}
void detector_destroy(deadlock_detector_t* detector) {
pthread_mutex_destroy(&detector->mutex);
free(detector->lock_owners);
free(detector->owned_locks);
free(detector);
}
// 检查死锁的辅助函数
int detect_deadlock(deadlock_detector_t* detector, pthread_t thread, pthread_mutex_t* mutex) {
pthread_mutex_lock(&detector->mutex);
// 简化版的死锁检测:检查是否形成循环等待
for (int i = 0; i < detector->max_locks; i++) {
if (detector->owned_locks[i] == mutex) {
pthread_t owner = detector->lock_owners[i];
if (pthread_equal(owner, thread)) {
// 同一个线程重复获取锁 - 需要递归锁
pthread_mutex_unlock(&detector->mutex);
return -1; // 可能的设计错误
}
// 这里可以实现更复杂的循环检测
printf("警告: 线程 %lu 等待被线程 %lu 持有的锁 %p\n",
(unsigned long)thread, (unsigned long)owner, (void*)mutex);
}
}
pthread_mutex_unlock(&detector->mutex);
return 0;
}
// 安全的锁包装器
typedef struct {
pthread_mutex_t mutex;
deadlock_detector_t* detector;
const char* name;
} safe_mutex_t;
void safe_mutex_init(safe_mutex_t* sm, deadlock_detector_t* detector, const char* name) {
pthread_mutex_init(&sm->mutex, NULL);
sm->detector = detector;
sm->name = name;
}
void safe_mutex_lock(safe_mutex_t* sm) {
pthread_t self = pthread_self();
// 死锁检测
if (detect_deadlock(sm->detector, self, &sm->mutex) != 0) {
printf("潜在死锁检测: 线程 %lu 尝试获取 %s\n",
(unsigned long)self, sm->name);
}
printf("线程 %lu: 等待锁 %s\n", (unsigned long)self, sm->name);
pthread_mutex_lock(&sm->mutex);
printf("线程 %lu: 获得锁 %s\n", (unsigned long)self, sm->name);
// 记录锁的所有权
pthread_mutex_lock(&sm->detector->mutex);
for (int i = 0; i < sm->detector->max_locks; i++) {
if (sm->detector->owned_locks[i] == NULL) {
sm->detector->owned_locks[i] = &sm->mutex;
sm->detector->lock_owners[i] = self;
break;
}
}
pthread_mutex_unlock(&sm->detector->mutex);
}
void safe_mutex_unlock(safe_mutex_t* sm) {
pthread_t self = pthread_self();
printf("线程 %lu: 释放锁 %s\n", (unsigned long)self, sm->name);
// 清除锁的所有权记录
pthread_mutex_lock(&sm->detector->mutex);
for (int i = 0; i < sm->detector->max_locks; i++) {
if (sm->detector->owned_locks[i] == &sm->mutex) {
sm->detector->owned_locks[i] = NULL;
break;
}
}
pthread_mutex_unlock(&sm->detector->mutex);
pthread_mutex_unlock(&sm->mutex);
}
// 死锁演示
safe_mutex_t mutex1, mutex2;
void* deadlock_thread1(void* arg) {
safe_mutex_lock(&mutex1);
usleep(100000); // 让另一个线程有机会获取第二个锁
safe_mutex_lock(&mutex2);
printf("线程1: 成功获取两个锁\n");
safe_mutex_unlock(&mutex2);
safe_mutex_unlock(&mutex1);
return NULL;
}
void* deadlock_thread2(void* arg) {
safe_mutex_lock(&mutex2);
usleep(100000); // 让另一个线程有机会获取第一个锁
safe_mutex_lock(&mutex1);
printf("线程2: 成功获取两个锁\n");
safe_mutex_unlock(&mutex1);
safe_mutex_unlock(&mutex2);
return NULL;
}
void demonstrate_deadlock_detection() {
deadlock_detector_t* detector = detector_create(10);
safe_mutex_init(&mutex1, detector, "互斥锁1");
safe_mutex_init(&mutex2, detector, "互斥锁2");
pthread_t t1, t2;
printf("=== 死锁检测演示 ===\n");
printf("注意: 这可能会产生死锁,但检测器会发出警告\n");
pthread_create(&t1, NULL, deadlock_thread1, NULL);
pthread_create(&t2, NULL, deadlock_thread2, NULL);
// 等待一段时间看是否发生死锁
sleep(3);
printf("主线程: 尝试取消死锁线程\n");
pthread_cancel(t1);
pthread_cancel(t2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
detector_destroy(detector);
printf("死锁演示结束\n");
}
int main() {
printf("多线程死锁检测与预防\n");
demonstrate_deadlock_detection();
return 0;
}
8.1.2 锁层次结构与死锁预防
通过强制锁的获取顺序来预防死锁。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// 锁层次系统
typedef struct {
pthread_mutex_t mutex;
int level; // 层次级别,数字越小优先级越高
const char* name;
} hierarchical_mutex_t;
void hierarchical_mutex_init(hierarchical_mutex_t* hm, int level, const char* name) {
pthread_mutex_init(&hm->mutex, NULL);
hm->level = level;
hm->name = name;
}
// 线程局部存储记录当前持有的最高级别锁
static __thread int current_level = 0;
void hierarchical_mutex_lock(hierarchical_mutex_t* hm) {
if (hm->level >= current_level) {
printf("锁层次违规! 当前级别: %d, 尝试获取: %d (%s)\n",
current_level, hm->level, hm->name);
// 在实际系统中,这里应该抛出异常或采取其他措施
return;
}
printf("获取锁 %s (级别: %d)\n", hm->name, hm->level);
pthread_mutex_lock(&hm->mutex);
current_level = hm->level;
}
void hierarchical_mutex_unlock(hierarchical_mutex_t* hm) {
printf("释放锁 %s (级别: %d)\n", hm->name, hm->level);
current_level = 0; // 简化:重置级别
pthread_mutex_unlock(&hm->mutex);
}
// 锁层次演示
hierarchical_mutex_t high_level_mutex = {.level = 1, .name = "高级锁"};
hierarchical_mutex_t medium_level_mutex = {.level = 2, .name = "中级锁"};
hierarchical_mutex_t low_level_mutex = {.level = 3, .name = "低级锁"};
void* correct_lock_order_thread(void* arg) {
printf("正确锁顺序线程开始\n");
// 正确的顺序:从高级别到低级别
hierarchical_mutex_lock(&high_level_mutex);
hierarchical_mutex_lock(&medium_level_mutex);
hierarchical_mutex_lock(&low_level_mutex);
printf("正确顺序: 成功获取所有锁\n");
hierarchical_mutex_unlock(&low_level_mutex);
hierarchical_mutex_unlock(&medium_level_mutex);
hierarchical_mutex_unlock(&high_level_mutex);
return NULL;
}
void* incorrect_lock_order_thread(void* arg) {
printf("错误锁顺序线程开始\n");
// 错误的顺序:从低级别开始
hierarchical_mutex_lock(&low_level_mutex);
// 这里应该会失败,因为试图获取更高级别的锁
hierarchical_mutex_lock(&high_level_mutex);
printf("错误顺序: 这行不应该打印\n");
hierarchical_mutex_unlock(&high_level_mutex);
hierarchical_mutex_unlock(&low_level_mutex);
return NULL;
}
void demonstrate_lock_hierarchy() {
hierarchical_mutex_init(&high_level_mutex, 1, "高级锁");
hierarchical_mutex_init(&medium_level_mutex, 2, "中级锁");
hierarchical_mutex_init(&low_level_mutex, 3, "低级锁");
pthread_t correct_thread, incorrect_thread;
printf("=== 锁层次结构演示 ===\n");
printf("\n1. 正确锁顺序测试:\n");
pthread_create(&correct_thread, NULL, correct_lock_order_thread, NULL);
pthread_join(correct_thread, NULL);
printf("\n2. 错误锁顺序测试:\n");
pthread_create(&incorrect_thread, NULL, incorrect_lock_order_thread, NULL);
pthread_join(incorrect_thread, NULL);
printf("\n锁层次演示完成\n");
}
int main() {
printf("锁层次结构与死锁预防\n");
demonstrate_lock_hierarchy();
return 0;
}
8.2 性能分析与优化
8.2.1 锁竞争分析
分析多线程程序中的锁竞争情况,识别性能瓶颈。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/sysinfo.h>
// 锁性能分析器
typedef struct {
pthread_mutex_t mutex;
long long lock_attempts;
long long lock_successes;
long long total_wait_time; // 纳秒
struct timespec last_lock_time;
} lock_profiler_t;
void profiler_init(lock_profiler_t* profiler) {
pthread_mutex_init(&profiler->mutex, NULL);
profiler->lock_attempts = 0;
profiler->lock_successes = 0;
profiler->total_wait_time = 0;
}
void profiler_record_lock_attempt(lock_profiler_t* profiler) {
__sync_fetch_and_add(&profiler->lock_attempts, 1);
}
void profiler_record_lock_success(lock_profiler_t* profiler, long long wait_time) {
__sync_fetch_and_add(&profiler->lock_successes, 1);
__sync_fetch_and_add(&profiler->total_wait_time, wait_time);
}
void profiler_report(lock_profiler_t* profiler, const char* lock_name) {
printf("=== 锁性能报告: %s ===\n", lock_name);
printf("锁尝试次数: %lld\n", profiler->lock_attempts);
printf("锁成功次数: %lld\n", profiler->lock_successes);
printf("总等待时间: %lld 纳秒\n", profiler->total_wait_time);
if (profiler->lock_successes > 0) {
printf("平均等待时间: %lld 纳秒\n",
profiler->total_wait_time / profiler->lock_successes);
}
double success_rate = (double)profiler->lock_successes / profiler->lock_attempts * 100;
printf("锁成功率: %.2f%%\n", success_rate);
if (success_rate < 80.0) {
printf("警告: 锁竞争激烈!\n");
}
}
// 带分析的锁
typedef struct {
pthread_mutex_t mutex;
lock_profiler_t profiler;
const char* name;
} analyzed_mutex_t;
void analyzed_mutex_init(analyzed_mutex_t* am, const char* name) {
pthread_mutex_init(&am->mutex, NULL);
profiler_init(&am->profiler);
am->name = name;
}
void analyzed_mutex_lock(analyzed_mutex_t* am) {
profiler_record_lock_attempt(&am->profiler);
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
pthread_mutex_lock(&am->mutex);
clock_gettime(CLOCK_MONOTONIC, &end);
long long wait_time = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
profiler_record_lock_success(&am->profiler, wait_time);
}
void analyzed_mutex_unlock(analyzed_mutex_t* am) {
pthread_mutex_unlock(&am->mutex);
}
void analyzed_mutex_report(analyzed_mutex_t* am) {
profiler_report(&am->profiler, am->name);
}
// 性能测试
analyzed_mutex_t test_mutex = {.name = "测试锁"};
const int NUM_OPERATIONS = 100000;
const int NUM_THREADS = 4;
void* performance_worker(void* arg) {
int thread_id = *(int*)arg;
for (int i = 0; i < NUM_OPERATIONS; i++) {
analyzed_mutex_lock(&test_mutex);
// 模拟一些工作
int result = 0;
for (int j = 0; j < 100; j++) {
result += j * j;
}
analyzed_mutex_unlock(&test_mutex);
}
printf("线程 %d 完成\n", thread_id);
return NULL;
}
void run_performance_test() {
analyzed_mutex_init(&test_mutex, "测试锁");
pthread_t threads[NUM_THREADS];
int thread_ids[NUM_THREADS];
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// 创建并启动工作线程
for (int i = 0; i < NUM_THREADS; i++) {
thread_ids[i] = i;
pthread_create(&threads[i], NULL, performance_worker, &thread_ids[i]);
}
// 等待所有线程完成
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long long total_time = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf("\n=== 性能测试结果 ===\n");
printf("总操作数: %d\n", NUM_OPERATIONS * NUM_THREADS);
printf("总时间: %lld 纳秒\n", total_time);
printf("吞吐量: %.2f 操作/秒\n",
(double)(NUM_OPERATIONS * NUM_THREADS) / total_time * 1e9);
analyzed_mutex_report(&test_mutex);
}
int main() {
printf("多线程性能分析与锁竞争检测\n");
run_performance_test();
return 0;
}
由于篇幅限制,先提供第七、八章的详细内容!!!
---------------------------------------------------------------------------------------------------------------------------------------更新于2025.11.18 下午
深入解析pthread.h:Linux多线程编程完全指南(第四部分)
第九章:高级多线程编程模式
9.1 线程池的高级实现与性能优化
9.1.1 高性能线程池设计
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
// 任务结构
typedef struct task {
void (*function)(void *arg);
void *arg;
struct task *next;
long long enqueue_time; // 入队时间(性能分析)
} task_t;
// 线程池统计信息
typedef struct {
long long tasks_completed;
long long total_wait_time; // 总等待时间(纳秒)
long long total_exec_time; // 总执行时间(纳秒)
long long max_wait_time;
long long max_exec_time;
} pool_stats_t;
// 高性能线程池
typedef struct {
// 任务队列
task_t *queue_head;
task_t *queue_tail;
int queue_size;
int queue_capacity;
// 线程管理
pthread_t *threads;
int thread_count;
int active_threads;
// 同步原语
pthread_mutex_t queue_mutex;
pthread_cond_t queue_not_empty;
pthread_cond_t queue_not_full;
pthread_cond_t all_tasks_done;
// 控制标志
int shutdown;
int drain; // 排空模式:不接受新任务,只处理现有任务
// 统计信息
pool_stats_t stats;
pthread_mutex_t stats_mutex;
// 性能优化
int use_spinlock; // 对短任务使用自旋锁
} thread_pool_t;
// 创建线程池
thread_pool_t* thread_pool_create(int thread_count, int queue_capacity, int use_spinlock) {
if (thread_count <= 0 || queue_capacity <= 0) {
return NULL;
}
thread_pool_t *pool = malloc(sizeof(thread_pool_t));
if (!pool) return NULL;
// 初始化基础字段
pool->queue_head = pool->queue_tail = NULL;
pool->queue_size = 0;
pool->queue_capacity = queue_capacity;
pool->thread_count = thread_count;
pool->active_threads = 0;
pool->shutdown = 0;
pool->drain = 0;
pool->use_spinlock = use_spinlock;
// 初始化统计信息
memset(&pool->stats, 0, sizeof(pool_stats_t));
// 初始化同步原语
if (pthread_mutex_init(&pool->queue_mutex, NULL) != 0) {
free(pool);
return NULL;
}
if (pthread_cond_init(&pool->queue_not_empty, NULL) != 0 ||
pthread_cond_init(&pool->queue_not_full, NULL) != 0 ||
pthread_cond_init(&pool->all_tasks_done, NULL) != 0) {
pthread_mutex_destroy(&pool->queue_mutex);
free(pool);
return NULL;
}
if (pthread_mutex_init(&pool->stats_mutex, NULL) != 0) {
pthread_mutex_destroy(&pool->queue_mutex);
pthread_cond_destroy(&pool->queue_not_empty);
pthread_cond_destroy(&pool->queue_not_full);
pthread_cond_destroy(&pool->all_tasks_done);
free(pool);
return NULL;
}
// 创建工作线程
pool->threads = malloc(sizeof(pthread_t) * thread_count);
if (!pool->threads) {
thread_pool_destroy(pool, 0);
return NULL;
}
for (int i = 0; i < thread_count; i++) {
if (pthread_create(&pool->threads[i], NULL, worker_thread, pool) != 0) {
// 创建失败,销毁已创建的线程
pool->thread_count = i; // 更新为成功创建的线程数
thread_pool_destroy(pool, 0);
return NULL;
}
pool->active_threads++;
}
return pool;
}
// 工作线程函数
void* worker_thread(void *arg) {
thread_pool_t *pool = (thread_pool_t*)arg;
while (1) {
task_t *task = NULL;
struct timespec wait_start, wait_end, exec_start, exec_end;
// 获取当前时间(等待开始)
clock_gettime(CLOCK_MONOTONIC, &wait_start);
pthread_mutex_lock(&pool->queue_mutex);
// 等待任务或关闭信号
while (pool->queue_size == 0 && !pool->shutdown) {
pthread_cond_wait(&pool->queue_not_empty, &pool->queue_mutex);
}
// 检查关闭条件
if (pool->shutdown && (pool->drain ? pool->queue_size == 0 : 1)) {
pool->active_threads--;
if (pool->active_threads == 0) {
pthread_cond_broadcast(&pool->all_tasks_done);
}
pthread_mutex_unlock(&pool->queue_mutex);
break;
}
// 获取任务
task = pool->queue_head;
if (task) {
pool->queue_head = task->next;
pool->queue_size--;
if (pool->queue_size == 0) {
pool->queue_tail = NULL;
}
// 通知生产者队列有空位
if (pool->queue_size == pool->queue_capacity - 1) {
pthread_cond_broadcast(&pool->queue_not_full);
}
}
pthread_mutex_unlock(&pool->queue_mutex);
// 获取等待结束时间
clock_gettime(CLOCK_MONOTONIC, &wait_end);
if (task) {
// 计算等待时间
long long wait_time = (wait_end.tv_sec - wait_start.tv_sec) * 1000000000LL +
(wait_end.tv_nsec - wait_start.tv_nsec);
// 执行任务
clock_gettime(CLOCK_MONOTONIC, &exec_start);
task->function(task->arg);
clock_gettime(CLOCK_MONOTONIC, &exec_end);
// 计算执行时间
long long exec_time = (exec_end.tv_sec - exec_start.tv_sec) * 1000000000LL +
(exec_end.tv_nsec - exec_start.tv_nsec);
// 更新统计信息
pthread_mutex_lock(&pool->stats_mutex);
pool->stats.tasks_completed++;
pool->stats.total_wait_time += wait_time;
pool->stats.total_exec_time += exec_time;
if (wait_time > pool->stats.max_wait_time) {
pool->stats.max_wait_time = wait_time;
}
if (exec_time > pool->stats.max_exec_time) {
pool->stats.max_exec_time = exec_time;
}
pthread_mutex_unlock(&pool->stats_mutex);
free(task);
}
}
return NULL;
}
// 提交任务(带超时)
int thread_pool_submit(thread_pool_t *pool, void (*function)(void *), void *arg, long timeout_ms) {
if (!pool || !function || pool->drain) {
return -1;
}
struct timespec ts;
if (timeout_ms > 0) {
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += timeout_ms / 1000;
ts.tv_nsec += (timeout_ms % 1000) * 1000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
}
pthread_mutex_lock(&pool->queue_mutex);
// 等待队列有空位
while (pool->queue_size >= pool->queue_capacity && !pool->shutdown && !pool->drain) {
if (timeout_ms > 0) {
if (pthread_cond_timedwait(&pool->queue_not_full, &pool->queue_mutex, &ts) == ETIMEDOUT) {
pthread_mutex_unlock(&pool->queue_mutex);
return -2; // 超时
}
} else {
pthread_cond_wait(&pool->queue_not_full, &pool->queue_mutex);
}
}
if (pool->shutdown || pool->drain) {
pthread_mutex_unlock(&pool->queue_mutex);
return -1;
}
// 创建新任务
task_t *task = malloc(sizeof(task_t));
if (!task) {
pthread_mutex_unlock(&pool->queue_mutex);
return -3; // 内存不足
}
task->function = function;
task->arg = arg;
task->next = NULL;
clock_gettime(CLOCK_MONOTONIC, &task->enqueue_time);
// 添加到队列
if (pool->queue_tail) {
pool->queue_tail->next = task;
} else {
pool->queue_head = task;
}
pool->queue_tail = task;
pool->queue_size++;
// 通知工作线程
pthread_cond_signal(&pool->queue_not_empty);
pthread_mutex_unlock(&pool->queue_mutex);
return 0;
}
// 获取统计信息
void thread_pool_get_stats(thread_pool_t *pool, pool_stats_t *stats) {
if (!pool || !stats) return;
pthread_mutex_lock(&pool->stats_mutex);
memcpy(stats, &pool->stats, sizeof(pool_stats_t));
pthread_mutex_unlock(&pool->stats_mutex);
}
// 销毁线程池
void thread_pool_destroy(thread_pool_t *pool, int drain) {
if (!pool) return;
pthread_mutex_lock(&pool->queue_mutex);
if (drain) {
// 排空模式:处理完所有任务再关闭
pool->drain = 1;
while (pool->queue_size > 0) {
pthread_cond_wait(&pool->all_tasks_done, &pool->queue_mutex);
}
}
pool->shutdown = 1;
pthread_cond_broadcast(&pool->queue_not_empty);
pthread_cond_broadcast(&pool->queue_not_full);
pthread_mutex_unlock(&pool->queue_mutex);
// 等待所有线程退出
for (int i = 0; i < pool->thread_count; i++) {
pthread_join(pool->threads[i], NULL);
}
// 清理剩余任务
task_t *task = pool->queue_head;
while (task) {
task_t *next = task->next;
free(task);
task = next;
}
// 销毁同步原语
pthread_mutex_destroy(&pool->queue_mutex);
pthread_mutex_destroy(&pool->stats_mutex);
pthread_cond_destroy(&pool->queue_not_empty);
pthread_cond_destroy(&pool->queue_not_full);
pthread_cond_destroy(&pool->all_tasks_done);
// 释放内存
free(pool->threads);
free(pool);
}
9.1.2 线程池性能测试与优化
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 测试任务:矩阵乘法
typedef struct {
int size;
double **a, **b, **result;
int start_row, end_row;
} matrix_task_t;
void matrix_multiply_task(void *arg) {
matrix_task_t *task = (matrix_task_t*)arg;
for (int i = task->start_row; i < task->end_row; i++) {
for (int j = 0; j < task->size; j++) {
task->result[i][j] = 0;
for (int k = 0; k < task->size; k++) {
task->result[i][j] += task->a[i][k] * task->b[k][j];
}
}
}
free(task);
}
// 创建测试矩阵
double** create_matrix(int size) {
double **matrix = malloc(size * sizeof(double*));
for (int i = 0; i < size; i++) {
matrix[i] = malloc(size * sizeof(double));
for (int j = 0; j < size; j++) {
matrix[i][j] = (double)rand() / RAND_MAX;
}
}
return matrix;
}
void free_matrix(double **matrix, int size) {
for (int i = 0; i < size; i++) {
free(matrix[i]);
}
free(matrix);
}
// 性能测试函数
void performance_test() {
const int MATRIX_SIZE = 200;
const int NUM_TASKS = 8; // 将工作分成8个任务
const int THREAD_COUNTS[] = {1, 2, 4, 8};
const int NUM_TESTS = sizeof(THREAD_COUNTS) / sizeof(THREAD_COUNTS[0]);
printf("=== 线程池性能测试 ===\n");
printf("矩阵大小: %dx%d\n", MATRIX_SIZE, MATRIX_SIZE);
printf("任务数量: %d\n", NUM_TASKS);
// 创建测试数据
double **a = create_matrix(MATRIX_SIZE);
double **b = create_matrix(MATRIX_SIZE);
double **result = create_matrix(MATRIX_SIZE);
for (int test = 0; test < NUM_TESTS; test++) {
int thread_count = THREAD_COUNTS[test];
printf("\n测试 %d: %d 个线程\n", test + 1, thread_count);
thread_pool_t *pool = thread_pool_create(thread_count, NUM_TASKS, 0);
if (!pool) {
printf("创建线程池失败\n");
continue;
}
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// 提交任务
int rows_per_task = MATRIX_SIZE / NUM_TASKS;
for (int i = 0; i < NUM_TASKS; i++) {
matrix_task_t *task = malloc(sizeof(matrix_task_t));
task->size = MATRIX_SIZE;
task->a = a;
task->b = b;
task->result = result;
task->start_row = i * rows_per_task;
task->end_row = (i == NUM_TASKS - 1) ? MATRIX_SIZE : (i + 1) * rows_per_task;
if (thread_pool_submit(pool, matrix_multiply_task, task, 0) != 0) {
free(task);
printf("提交任务失败\n");
}
}
// 等待所有任务完成
thread_pool_destroy(pool, 1); // 排空模式关闭
clock_gettime(CLOCK_MONOTONIC, &end);
long long elapsed = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf("执行时间: %.3f 秒\n", elapsed / 1e9);
// 获取统计信息
pool_stats_t stats;
thread_pool_get_stats(pool, &stats);
printf("完成任务: %lld\n", stats.tasks_completed);
if (stats.tasks_completed > 0) {
printf("平均等待时间: %.3f 毫秒\n",
(stats.total_wait_time / stats.tasks_completed) / 1e6);
printf("平均执行时间: %.3f 毫秒\n",
(stats.total_exec_time / stats.tasks_completed) / 1e6);
}
}
// 清理
free_matrix(a, MATRIX_SIZE);
free_matrix(b, MATRIX_SIZE);
free_matrix(result, MATRIX_SIZE);
}
int main() {
printf("高级线程池性能测试\n");
performance_test();
return 0;
}
9.2 无锁编程与原子操作
9.2.1 原子操作的高级应用
c
#include <stdatomic.h>
#include <stdio.h>
#include <pthread.h>
#include <stdbool.h>
// 无锁栈实现
typedef struct lock_free_node {
void *data;
struct lock_free_node *next;
} lock_free_node_t;
typedef struct {
atomic_uintptr_t top; // 使用atomic_uintptr_t来保证原子性
atomic_size_t count;
} lock_free_stack_t;
void lock_free_stack_init(lock_free_stack_t *stack) {
atomic_store(&stack->top, (uintptr_t)NULL);
atomic_store(&stack->count, 0);
}
bool lock_free_stack_push(lock_free_stack_t *stack, void *data) {
lock_free_node_t *new_node = malloc(sizeof(lock_free_node_t));
if (!new_node) return false;
new_node->data = data;
uintptr_t current_top;
do {
current_top = atomic_load(&stack->top);
new_node->next = (lock_free_node_t*)current_top;
} while (!atomic_compare_exchange_weak(&stack->top, ¤t_top,
(uintptr_t)new_node));
atomic_fetch_add(&stack->count, 1);
return true;
}
void* lock_free_stack_pop(lock_free_stack_t *stack) {
uintptr_t current_top;
lock_free_node_t *next;
do {
current_top = atomic_load(&stack->top);
if (current_top == (uintptr_t)NULL) {
return NULL; // 栈为空
}
lock_free_node_t *current_node = (lock_free_node_t*)current_top;
next = current_node->next;
} while (!atomic_compare_exchange_weak(&stack->top, ¤t_top,
(uintptr_t)next));
lock_free_node_t *popped_node = (lock_free_node_t*)current_top;
void *data = popped_node->data;
free(popped_node);
atomic_fetch_sub(&stack->count, 1);
return data;
}
size_t lock_free_stack_size(lock_free_stack_t *stack) {
return atomic_load(&stack->count);
}
// 无锁队列实现(Michael-Scott算法)
typedef struct {
atomic_uintptr_t head;
atomic_uintptr_t tail;
atomic_size_t count;
} lock_free_queue_t;
typedef struct lf_queue_node {
void *data;
atomic_uintptr_t next;
} lf_queue_node_t;
void lock_free_queue_init(lock_free_queue_t *queue) {
lf_queue_node_t *dummy = malloc(sizeof(lf_queue_node_t));
dummy->data = NULL;
atomic_store(&dummy->next, (uintptr_t)NULL);
atomic_store(&queue->head, (uintptr_t)dummy);
atomic_store(&queue->tail, (uintptr_t)dummy);
atomic_store(&queue->count, 0);
}
bool lock_free_queue_enqueue(lock_free_queue_t *queue, void *data) {
lf_queue_node_t *new_node = malloc(sizeof(lf_queue_node_t));
if (!new_node) return false;
new_node->data = data;
atomic_store(&new_node->next, (uintptr_t)NULL);
uintptr_t tail, next;
while (1) {
tail = atomic_load(&queue->tail);
lf_queue_node_t *tail_node = (lf_queue_node_t*)tail;
next = atomic_load(&tail_node->next);
if (tail == atomic_load(&queue->tail)) {
if (next == (uintptr_t)NULL) {
if (atomic_compare_exchange_weak(&tail_node->next, &next,
(uintptr_t)new_node)) {
break;
}
} else {
atomic_compare_exchange_weak(&queue->tail, &tail, next);
}
}
}
atomic_compare_exchange_weak(&queue->tail, &tail, (uintptr_t)new_node);
atomic_fetch_add(&queue->count, 1);
return true;
}
void* lock_free_queue_dequeue(lock_free_queue_t *queue) {
uintptr_t head, tail, next;
void *data;
while (1) {
head = atomic_load(&queue->head);
tail = atomic_load(&queue->tail);
lf_queue_node_t *head_node = (lf_queue_node_t*)head;
next = atomic_load(&head_node->next);
if (head == atomic_load(&queue->head)) {
if (head == tail) {
if (next == (uintptr_t)NULL) {
return NULL; // 队列为空
}
atomic_compare_exchange_weak(&queue->tail, &tail, next);
} else {
data = ((lf_queue_node_t*)next)->data;
if (atomic_compare_exchange_weak(&queue->head, &head, next)) {
break;
}
}
}
}
free((lf_queue_node_t*)head);
atomic_fetch_sub(&queue->count, 1);
return data;
}
// 性能对比测试
void* stack_test_thread(void *arg) {
lock_free_stack_t *stack = (lock_free_stack_t*)arg;
for (int i = 0; i < 10000; i++) {
int *value = malloc(sizeof(int));
*value = i;
lock_free_stack_push(stack, value);
if (i % 2 == 0) {
void *popped = lock_free_stack_pop(stack);
if (popped) free(popped);
}
}
return NULL;
}
void performance_comparison() {
printf("=== 无锁数据结构性能测试 ===\n");
lock_free_stack_t stack;
lock_free_stack_init(&stack);
const int NUM_THREADS = 4;
pthread_t threads[NUM_THREADS];
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < NUM_THREADS; i++) {
pthread_create(&threads[i], NULL, stack_test_thread, &stack);
}
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long long elapsed = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf("无锁栈测试完成\n");
printf("线程数: %d\n", NUM_THREADS);
printf("总操作数: %d\n", NUM_THREADS * 10000);
printf("总时间: %.3f 秒\n", elapsed / 1e9);
printf("操作吞吐量: %.2f 操作/秒\n",
(NUM_THREADS * 10000.0) / (elapsed / 1e9));
printf("最终栈大小: %zu\n", lock_free_stack_size(&stack));
// 清理剩余节点
while (lock_free_stack_pop(&stack)) {
// 释放所有剩余节点
}
}
int main() {
printf("无锁编程与原子操作\n");
performance_comparison();
return 0;
}
第十章:实际项目案例研究
10.1 高性能网络服务器
10.1.1 Reactor模式网络服务器
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#define MAX_EVENTS 1024
#define BUFFER_SIZE 4096
#define MAX_CLIENTS 10000
// 客户端会话
typedef struct {
int fd;
struct sockaddr_in addr;
char read_buffer[BUFFER_SIZE];
int read_len;
char write_buffer[BUFFER_SIZE];
int write_len;
time_t last_activity;
} client_session_t;
// Reactor服务器
typedef struct {
int epoll_fd;
int listen_fd;
client_session_t *clients[MAX_CLIENTS];
pthread_mutex_t clients_mutex;
// 线程池
thread_pool_t *thread_pool;
// 统计信息
atomic_long total_connections;
atomic_long current_connections;
atomic_long total_requests;
} reactor_server_t;
// 设置非阻塞IO
int set_nonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) return -1;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
// 初始化服务器
reactor_server_t* server_create(int port, int thread_count) {
reactor_server_t *server = malloc(sizeof(reactor_server_t));
if (!server) return NULL;
memset(server, 0, sizeof(reactor_server_t));
// 创建epoll实例
server->epoll_fd = epoll_create1(0);
if (server->epoll_fd == -1) {
free(server);
return NULL;
}
// 创建监听socket
server->listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server->listen_fd == -1) {
close(server->epoll_fd);
free(server);
return NULL;
}
// 设置SO_REUSEADDR
int opt = 1;
setsockopt(server->listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 绑定地址
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(server->listen_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
close(server->listen_fd);
close(server->epoll_fd);
free(server);
return NULL;
}
// 开始监听
if (listen(server->listen_fd, SOMAXCONN) == -1) {
close(server->listen_fd);
close(server->epoll_fd);
free(server);
return NULL;
}
// 设置非阻塞
set_nonblocking(server->listen_fd);
// 添加监听socket到epoll
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET; // 边缘触发模式
ev.data.fd = server->listen_fd;
if (epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, server->listen_fd, &ev) == -1) {
close(server->listen_fd);
close(server->epoll_fd);
free(server);
return NULL;
}
// 初始化互斥锁
pthread_mutex_init(&server->clients_mutex, NULL);
// 创建线程池
server->thread_pool = thread_pool_create(thread_count, 1000, 0);
if (!server->thread_pool) {
close(server->listen_fd);
close(server->epoll_fd);
pthread_mutex_destroy(&server->clients_mutex);
free(server);
return NULL;
}
// 初始化原子变量
atomic_store(&server->total_connections, 0);
atomic_store(&server->current_connections, 0);
atomic_store(&server->total_requests, 0);
printf("服务器初始化完成,监听端口 %d\n", port);
return server;
}
// 处理HTTP请求的任务
typedef struct {
reactor_server_t *server;
client_session_t *session;
} http_task_t;
void http_request_handler(void *arg) {
http_task_t *task = (http_task_t*)arg;
client_session_t *session = task->session;
reactor_server_t *server = task->server;
// 简单的HTTP请求解析
char *request = session->read_buffer;
// 检查是否收到完整的HTTP请求(以\r\n\r\n结尾)
char *end_of_headers = strstr(request, "\r\n\r\n");
if (!end_of_headers) {
// 请求不完整,等待更多数据
free(task);
return;
}
// 解析请求行
char method[16], path[256], version[16];
sscanf(request, "%15s %255s %15s", method, path, version);
// 生成简单的HTTP响应
const char *response_template =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n"
"Connection: keep-alive\r\n"
"\r\n"
"Hello from reactor server! Path: %s";
char response_body[512];
snprintf(response_body, sizeof(response_body), "Hello from reactor server! Path: %s", path);
snprintf(session->write_buffer, sizeof(session->write_buffer),
response_template, strlen(response_body), path);
strcat(session->write_buffer, response_body);
session->write_len = strlen(session->write_buffer);
// 更新活动时间
session->last_activity = time(NULL);
// 更新统计信息
atomic_fetch_add(&server->total_requests, 1);
free(task);
}
// 接受新连接
void accept_connection(reactor_server_t *server) {
while (1) {
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int client_fd = accept(server->listen_fd,
(struct sockaddr*)&client_addr, &addr_len);
if (client_fd == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 没有更多连接了
break;
} else {
perror("accept");
break;
}
}
// 设置非阻塞
set_nonblocking(client_fd);
// 创建客户端会话
client_session_t *session = malloc(sizeof(client_session_t));
if (!session) {
close(client_fd);
continue;
}
memset(session, 0, sizeof(client_session_t));
session->fd = client_fd;
memcpy(&session->addr, &client_addr, sizeof(client_addr));
session->last_activity = time(NULL);
// 添加到客户端列表
pthread_mutex_lock(&server->clients_mutex);
int added = 0;
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] == NULL) {
server->clients[i] = session;
added = 1;
break;
}
}
pthread_mutex_unlock(&server->clients_mutex);
if (!added) {
// 达到最大客户端数
free(session);
close(client_fd);
continue;
}
// 添加到epoll
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
ev.data.ptr = session;
if (epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
perror("epoll_ctl add client");
pthread_mutex_lock(&server->clients_mutex);
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] == session) {
server->clients[i] = NULL;
break;
}
}
pthread_mutex_unlock(&server->clients_mutex);
free(session);
close(client_fd);
continue;
}
// 更新统计信息
atomic_fetch_add(&server->total_connections, 1);
atomic_fetch_add(&server->current_connections, 1);
printf("新连接: %s:%d (FD: %d)\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_fd);
}
}
// 处理客户端数据
void handle_client_data(reactor_server_t *server, client_session_t *session, uint32_t events) {
if (events & EPOLLRDHUP) {
// 连接关闭
printf("连接关闭: FD %d\n", session->fd);
goto close_connection;
}
if (events & EPOLLIN) {
// 读取数据
while (1) {
int n = read(session->fd,
session->read_buffer + session->read_len,
sizeof(session->read_buffer) - session->read_len - 1);
if (n > 0) {
session->read_len += n;
session->read_buffer[session->read_len] = '\0';
session->last_activity = time(NULL);
// 检查是否收到完整请求
if (strstr(session->read_buffer, "\r\n\r\n")) {
// 提交到线程池处理
http_task_t *task = malloc(sizeof(http_task_t));
task->server = server;
task->session = session;
if (thread_pool_submit(server->thread_pool, http_request_handler, task, 0) != 0) {
free(task);
}
}
} else if (n == 0) {
// 连接关闭
goto close_connection;
} else {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 没有更多数据了
break;
} else {
perror("read");
goto close_connection;
}
}
}
}
if (events & EPOLLOUT) {
// 写入数据
if (session->write_len > 0) {
int n = write(session->fd, session->write_buffer, session->write_len);
if (n > 0) {
// 移动剩余数据
memmove(session->write_buffer, session->write_buffer + n, session->write_len - n);
session->write_len -= n;
} else if (n == -1 && errno != EAGAIN) {
perror("write");
goto close_connection;
}
}
// 如果没有更多数据要写,停止监听写事件
if (session->write_len == 0) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
ev.data.ptr = session;
epoll_ctl(server->epoll_fd, EPOLL_CTL_MOD, session->fd, &ev);
}
}
return;
close_connection:
// 关闭连接
close(session->fd);
// 从epoll移除
epoll_ctl(server->epoll_fd, EPOLL_CTL_DEL, session->fd, NULL);
// 从客户端列表移除
pthread_mutex_lock(&server->clients_mutex);
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] == session) {
server->clients[i] = NULL;
break;
}
}
pthread_mutex_unlock(&server->clients_mutex);
atomic_fetch_sub(&server->current_connections, 1);
free(session);
}
// 服务器主循环
void server_run(reactor_server_t *server) {
struct epoll_event events[MAX_EVENTS];
printf("服务器开始运行...\n");
while (1) {
int nfds = epoll_wait(server->epoll_fd, events, MAX_EVENTS, 1000);
for (int i = 0; i < nfds; i++) {
if (events[i].data.fd == server->listen_fd) {
// 新连接
accept_connection(server);
} else {
// 客户端事件
client_session_t *session = (client_session_t*)events[i].data.ptr;
handle_client_data(server, session, events[i].events);
}
}
// 定期清理超时连接(简化版)
static time_t last_cleanup = 0;
time_t now = time(NULL);
if (now - last_cleanup > 30) { // 每30秒清理一次
// 这里可以实现连接超时清理
last_cleanup = now;
}
}
}
// 显示服务器状态
void server_status(reactor_server_t *server) {
printf("\n=== 服务器状态 ===\n");
printf("总连接数: %ld\n", atomic_load(&server->total_connections));
printf("当前连接数: %ld\n", atomic_load(&server->current_connections));
printf("总请求数: %ld\n", atomic_load(&server->total_requests));
// 线程池统计
pool_stats_t stats;
thread_pool_get_stats(server->thread_pool, &stats);
printf("线程池完成任务: %lld\n", stats.tasks_completed);
}
int main() {
printf("高性能Reactor模式网络服务器\n");
reactor_server_t *server = server_create(8080, 8); // 8个工作线程
if (!server) {
printf("服务器创建失败\n");
return 1;
}
// 启动服务器
server_run(server);
// 注意:server_run是阻塞的,正常情况下不会返回
// 在实际应用中,应该处理信号和优雅关闭
return 0;
}
由于篇幅限制,我提供了第九、十章的详细内容,涵盖了高级线程池实现、无锁编程和实际的高性能网络服务器案例。这些内容展示了如何将pthread.h的各种特性应用于实际的高性能系统中。
##### 代码模式:
code:
1. 头文件基础信息
c
/* Copyright (C) 2002-2024 Free Software Foundation, Inc.
GNU C Library 的线程支持头文件 */
#ifndef _PTHREAD_H
#define _PTHREAD_H 1
关键点:
这是 GNU C 库的一部分,遵循 LGPL 许可证
使用经典的头文件保护宏防止重复包含
#define _PTHREAD_H 1 中的 1 是标识符,表示已定义
2. 包含的依赖头文件
c
#include <features.h> // 特性宏定义
#include <sched.h> // 调度相关
#include <time.h> // 时间处理
#include <bits/endian.h> // 字节序定义
#include <bits/pthreadtypes.h> // 线程类型定义
#include <bits/setjmp.h> // 跳转相关
// ... 其他架构相关头文件
3. 核心数据类型和枚举定义
3.1 线程分离状态
c
enum {
PTHREAD_CREATE_JOINABLE, // 可连接线程(默认)
PTHREAD_CREATE_DETACHED // 分离线程
};
实际应用对比:
状态 资源回收 能否获取返回值 使用场景
JOINABLE 需手动pthread_join 可以 需要线程执行结果的场景
DETACHED 自动回收 不可以 后台任务、守护线程
3.2 互斥锁类型
c
enum {
PTHREAD_MUTEX_TIMED_NP, // 普通锁(默认)
PTHREAD_MUTEX_RECURSIVE_NP, // 递归锁
PTHREAD_MUTEX_ERRORCHECK_NP, // 错误检查锁
PTHREAD_MUTEX_ADAPTIVE_NP // 自适应锁
};
锁类型详解表格:
锁类型 重入性 错误检查 性能 适用场景
NORMAL 不可重入 无检查 最高 简单同步
RECURSIVE 可重入 有检查 较低 递归函数
ERRORCHECK 不可重入 有检查 中等 调试开发
ADAPTIVE 不可重入 无检查 自适应 高竞争场景
4. 核心函数分类解析
4.1 线程生命周期管理
创建线程:
c
int pthread_create(pthread_t *__newthread,
const pthread_attr_t *__attr,
void *(*__start_routine) (void *),
void *__restrict __arg);
代码示例:
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// 线程函数
void* thread_function(void* arg) {
int thread_num = *(int*)arg;
printf("线程 %d 正在运行\n", thread_num);
return NULL;
}
int main() {
pthread_t threads[3];
int thread_args[3] = {1, 2, 3};
// 创建3个线程
for (int i = 0; i < 3; i++) {
if (pthread_create(&threads[i], NULL, thread_function, &thread_args[i]) != 0) {
perror("pthread_create failed");
exit(1);
}
}
// 等待所有线程完成
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
printf("所有线程执行完毕\n");
return 0;
}
线程终止:
c
void pthread_exit(void *__retval); // 线程自行退出
int pthread_join(pthread_t __th, void **__thread_return); // 等待线程结束
int pthread_detach(pthread_t __th); // 分离线程
4.2 互斥锁操作详解
基础使用模式:
c
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int shared_data = 0;
void* increment_thread(void* arg) {
for (int i = 0; i < 100000; i++) {
pthread_mutex_lock(&mutex);
shared_data++;
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, increment_thread, NULL);
pthread_create(&t2, NULL, increment_thread, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("最终结果: %d (期望: 200000)\n", shared_data);
return 0;
}
高级锁操作:
c
// 带超时的锁获取
int pthread_mutex_timedlock(pthread_mutex_t *__mutex,
const struct timespec *__abstime);
// 带时钟的锁获取
int pthread_mutex_clocklock(pthread_mutex_t *__mutex,
clockid_t __clockid,
const struct timespec *__abstime);
4.3 条件变量深度解析
生产者-消费者模式示例:
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#define BUFFER_SIZE 10
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_producer = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_consumer = PTHREAD_COND_INITIALIZER;
int buffer[BUFFER_SIZE];
int count = 0; // 缓冲区中元素数量
void* producer(void* arg) {
int item = 0;
while (1) {
pthread_mutex_lock(&mutex);
// 缓冲区满,等待消费者消费
while (count == BUFFER_SIZE) {
pthread_cond_wait(&cond_producer, &mutex);
}
// 生产项目
buffer[count] = item++;
count++;
printf("生产者生产: %d, 缓冲区大小: %d\n", item, count);
// 通知消费者
pthread_cond_signal(&cond_consumer);
pthread_mutex_unlock(&mutex);
usleep(100000); // 100ms
}
return NULL;
}
void* consumer(void* arg) {
while (1) {
pthread_mutex_lock(&mutex);
// 缓冲区空,等待生产者生产
while (count == 0) {
pthread_cond_wait(&cond_consumer, &mutex);
}
// 消费项目
int item = buffer[count - 1];
count--;
printf("消费者消费: %d, 缓冲区大小: %d\n", item, count);
// 通知生产者
pthread_cond_signal(&cond_producer);
pthread_mutex_unlock(&mutex);
usleep(150000); // 150ms
}
return NULL;
}
5. 线程属性设置详解
完整属性设置示例:
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void* demo_thread(void* arg) {
printf("自定义属性线程运行中...\n");
return NULL;
}
int main() {
pthread_t thread;
pthread_attr_t attr;
// 1. 初始化属性对象
if (pthread_attr_init(&attr) != 0) {
perror("pthread_attr_init");
exit(1);
}
// 2. 设置分离状态
if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) != 0) {
perror("pthread_attr_setdetachstate");
exit(1);
}
// 3. 设置栈大小 (1MB)
size_t stack_size = 1024 * 1024;
if (pthread_attr_setstacksize(&attr, stack_size) != 0) {
perror("pthread_attr_setstacksize");
exit(1);
}
// 4. 设置调度策略
if (pthread_attr_setschedpolicy(&attr, SCHED_OTHER) != 0) {
perror("pthread_attr_setschedpolicy");
exit(1);
}
// 5. 创建线程
if (pthread_create(&thread, &attr, demo_thread, NULL) != 0) {
perror("pthread_create");
exit(1);
}
// 6. 销毁属性对象
pthread_attr_destroy(&attr);
// 7. 等待线程结束
pthread_join(thread, NULL);
printf("线程执行完成\n");
return 0;
}
6. 高级特性解析
6.1 线程取消机制
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 清理处理函数
void cleanup_handler(void* arg) {
printf("清理资源: %s\n", (char*)arg);
}
void* cancellable_thread(void* arg) {
// 注册清理处理程序
pthread_cleanup_push(cleanup_handler, "线程取消时的清理");
// 启用取消
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
printf("线程开始运行,5秒后将被取消\n");
for (int i = 0; i < 5; i++) {
printf("运行中... %d\n", i + 1);
sleep(1);
pthread_testcancel(); // 取消点
}
pthread_cleanup_pop(0); // 不执行清理(正常退出)
return NULL;
}
int main() {
pthread_t thread;
pthread_create(&thread, NULL, cancellable_thread, NULL);
sleep(3); // 等待3秒
printf("主线程取消工作线程\n");
pthread_cancel(thread);
pthread_join(thread, NULL);
printf("工作线程已被取消\n");
return 0;
}
6.2 线程局部存储 (TLS)
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// 创建线程特定数据键
pthread_key_t thread_log_key;
// 析构函数
void close_thread_log(void* thread_log) {
fclose((FILE*)thread_log);
printf("线程日志文件已关闭\n");
}
void* worker_thread(void* arg) {
int thread_id = *(int*)arg;
// 为每个线程创建独立的日志文件
char filename[100];
sprintf(filename, "thread_%d.log", thread_id);
FILE* thread_log = fopen(filename, "w");
if (thread_log != NULL) {
// 设置线程特定数据
pthread_setspecific(thread_log_key, thread_log);
fprintf(thread_log, "线程 %d 开始工作\n", thread_id);
}
// 获取线程特定数据并使用
FILE* log = pthread_getspecific(thread_log_key);
if (log != NULL) {
fprintf(log, "线程 %d 正在处理数据...\n", thread_id);
}
return NULL;
}
int main() {
pthread_t threads[3];
int thread_ids[3] = {1, 2, 3};
// 创建线程特定数据键
pthread_key_create(&thread_log_key, close_thread_log);
// 创建工作线程
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, worker_thread, &thread_ids[i]);
}
// 等待所有线程完成
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
// 销毁键
pthread_key_delete(thread_log_key);
printf("所有线程执行完毕\n");
return 0;
}
7. 同步原语对比分析
同步机制 适用场景 优点 缺点 性能
互斥锁 保护临界区 简单可靠 可能死锁 高
读写锁 读多写少 并发读 实现复杂 中高
条件变量 线程间通信 高效等待 需配合互斥锁 高
自旋锁 短临界区 无上下文切换 忙等待消耗CPU 极高
屏障 多阶段计算 同步点控制 灵活性差 中
8. 错误处理最佳实践
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define CHECK_PTHREAD_CALL(call, msg) \
do { \
int result = (call); \
if (result != 0) { \
errno = result; \
perror(msg); \
exit(EXIT_FAILURE); \
} \
} while(0)
void* safe_thread(void* arg) {
printf("安全线程运行\n");
return NULL;
}
int main() {
pthread_t thread;
pthread_attr_t attr;
// 使用宏进行错误检查
CHECK_PTHREAD_CALL(pthread_attr_init(&attr), "pthread_attr_init");
CHECK_PTHREAD_CALL(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE),
"pthread_attr_setdetachstate");
CHECK_PTHREAD_CALL(pthread_create(&thread, &attr, safe_thread, NULL),
"pthread_create");
CHECK_PTHREAD_CALL(pthread_join(thread, NULL), "pthread_join");
CHECK_PTHREAD_CALL(pthread_attr_destroy(&attr), "pthread_attr_destroy");
printf("所有操作成功完成\n");
return 0;
}
9. 性能优化技巧
9.1 避免锁竞争的技巧
c
#include <pthread.h>
#include <stdio.h>
// 细粒度锁 - 每个数据结构独立的锁
typedef struct {
pthread_mutex_t lock;
int data;
} protected_int;
// 锁分层 - 避免死锁的固定加锁顺序
void safe_operation(protected_int *a, protected_int *b) {
// 总是先锁地址小的那个
if (a < b) {
pthread_mutex_lock(&a->lock);
pthread_mutex_lock(&b->lock);
} else {
pthread_mutex_lock(&b->lock);
pthread_mutex_lock(&a->lock);
}
// 执行操作
a->data += b->data;
// 解锁顺序与加锁顺序相反
pthread_mutex_unlock(&b->lock);
pthread_mutex_unlock(&a->lock);
}
10. 编译和链接
编译命令:
bash
# 编译多线程程序
gcc -pthread program.c -o program
# 或者传统方式
gcc -lpthread program.c -o program
关键编译标志:
-pthread: 定义必要的宏并链接线程库
-D_REENTRANT: 定义可重入宏(现代编译器自动处理)
总结
pthread.h 提供了完整的 POSIX 线程编程接口,包括:
线程管理 - 创建、终止、连接、分离
同步机制 - 互斥锁、条件变量、读写锁、屏障
线程安全 - 线程特定数据、取消机制
性能控制 - 属性设置、调度控制
掌握这些 API 对于开发高性能、并发安全的应用程序至关重要。在实际使用中,要注意正确的错误处理和资源管理,避免常见的多线程陷阱如死锁、竞态条件等。
深入解析pthread.h:Linux多线程编程完全指南(第二部分)
第五章:线程同步原语深度剖析
5.1 互斥锁的高级特性与实现原理
5.1.1 互斥锁的内存布局与内核实现
在Linux系统中,互斥锁的实现经历了从用户态到内核态的演进。让我们深入分析其内部结构:
c
// pthreadtypes.h 中互斥锁的典型定义
typedef union {
struct __pthread_mutex_s {
int __lock; // 锁状态
unsigned int __count; // 递归计数
int __owner; // 当前持有者线程ID
unsigned int __nusers; // 用户计数
int __kind; // 锁类型
int __spins; // 自旋计数(自适应锁)
} __data;
char __size[__SIZEOF_PTHREAD_MUTEX_T]; // 总大小
long __align; // 对齐
} pthread_mutex_t;
互斥锁状态转换图:
text
锁状态机:
┌───────────┐ pthread_mutex_lock() ┌───────────┐
│ 未锁定 │ ────────────────────────> │ 已锁定 │
└───────────┘ └───────────┘
^ │
│ pthread_mutex_unlock() │
└──────────────────────────────────────┘
锁竞争处理策略对比表:
竞争处理策略 实现机制 适用场景 性能特点
直接阻塞 线程进入睡眠等待队列 锁持有时间长 上下文切换开销大
自旋等待 循环检查锁状态 锁持有时间短 CPU占用高,响应快
适应性锁 先自旋后阻塞 中等持有时间 平衡性能
队列锁 FIFO等待队列 公平性要求高 避免饥饿
5.1.2 递归锁的实现原理与应用场景
递归锁(Recursive Mutex)允许同一个线程多次获取同一个锁而不会死锁。这在递归函数或可重入代码中非常有用。
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 递归函数示例
void recursive_function(int depth, pthread_mutex_t *mutex) {
if (depth <= 0) return;
printf("深度 %d: 尝试获取锁...\n", depth);
pthread_mutex_lock(mutex);
printf("深度 %d: 成功获取锁\n", depth);
// 模拟工作
usleep(100000);
// 递归调用
recursive_function(depth - 1, mutex);
printf("深度 %d: 释放锁\n", depth);
pthread_mutex_unlock(mutex);
}
int main() {
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
// 设置递归锁属性
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
// 初始化递归锁
pthread_mutex_init(&mutex, &attr);
printf("开始递归锁测试...\n");
recursive_function(3, &mutex);
printf("递归锁测试完成\n");
// 清理资源
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&attr);
return 0;
}
递归锁内部计数机制:
c
// 伪代码:递归锁实现原理
struct recursive_mutex {
pthread_t owner; // 当前持有者
int count; // 递归计数
pthread_mutex_t internal_lock; // 内部保护锁
};
void recursive_lock(struct recursive_mutex *rmutex) {
pthread_t self = pthread_self();
pthread_mutex_lock(&rmutex->internal_lock);
if (rmutex->count > 0 && pthread_equal(rmutex->owner, self)) {
// 同一个线程重复获取锁
rmutex->count++;
} else {
// 等待真正的锁获取
while (rmutex->count > 0) {
pthread_mutex_unlock(&rmutex->internal_lock);
usleep(1000); // 短暂等待
pthread_mutex_lock(&rmutex->internal_lock);
}
rmutex->owner = self;
rmutex->count = 1;
}
pthread_mutex_unlock(&rmutex->internal_lock);
}
void recursive_unlock(struct recursive_mutex *rmutex) {
pthread_mutex_lock(&rmutex->internal_lock);
if (rmutex->count > 0 && pthread_equal(rmutex->owner, pthread_self())) {
rmutex->count--;
if (rmutex->count == 0) {
rmutex->owner = 0; // 清除所有者
}
}
pthread_mutex_unlock(&rmutex->internal_lock);
}
5.1.3 错误检查锁的实际应用
错误检查锁(Error-checking Mutex)能够在开发阶段帮助发现锁使用错误。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define CHECK(expr, msg) \
do { \
int ret = (expr); \
if (ret != 0) { \
fprintf(stderr, "%s: %s\n", msg, strerror(ret)); \
exit(EXIT_FAILURE); \
} \
} while(0)
void demonstrate_error_checking() {
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
// 创建错误检查锁
CHECK(pthread_mutexattr_init(&attr), "初始化属性失败");
CHECK(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK),
"设置错误检查类型失败");
CHECK(pthread_mutex_init(&mutex, &attr), "初始化互斥锁失败");
// 正确的使用方式
printf("测试1: 正常加锁解锁...\n");
CHECK(pthread_mutex_lock(&mutex), "加锁失败");
CHECK(pthread_mutex_unlock(&mutex), "解锁失败");
// 检测重复解锁错误
printf("测试2: 检测重复解锁错误...\n");
CHECK(pthread_mutex_lock(&mutex), "加锁失败");
CHECK(pthread_mutex_unlock(&mutex), "第一次解锁失败");
// 这里会产生错误:重复解锁
int result = pthread_mutex_unlock(&mutex);
if (result != 0) {
printf("检测到错误: 重复解锁 (%s)\n", strerror(result));
}
// 检测未持有锁时解锁的错误
printf("测试3: 检测未持有锁时解锁...\n");
result = pthread_mutex_unlock(&mutex);
if (result != 0) {
printf("检测到错误: 未持有锁时解锁 (%s)\n", strerror(result));
}
// 清理资源
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&attr);
}
int main() {
printf("错误检查锁演示开始\n");
demonstrate_error_checking();
printf("错误检查锁演示结束\n");
return 0;
}
5.2 条件变量的高级用法与性能优化
5.2.1 条件变量的内部实现机制
条件变量的实现依赖于内核的futex(快速用户空间互斥锁)机制,让我们深入了解其工作原理:
c
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
// 条件变量的内部状态模拟
struct condition_internal {
pthread_mutex_t *mutex; // 关联的互斥锁
int waiters; // 等待线程数
int signals; // 信号计数
struct timespec timeout; // 超时时间
};
void condition_variable_analysis() {
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
printf("条件变量大小: %zu 字节\n", sizeof(cond));
printf("互斥锁大小: %zu 字节\n", sizeof(mutex));
// 分析条件变量的内存布局
unsigned char *cond_bytes = (unsigned char*)&cond;
printf("条件变量内存布局: ");
for (size_t i = 0; i < sizeof(cond); i++) {
printf("%02x ", cond_bytes[i]);
}
printf("\n");
}
条件变量状态转换图:
text
条件变量状态机:
┌─────────────┐ pthread_cond_wait() ┌─────────────┐
│ 无等待 │ ───────────────────────> │ 等待中 │
└─────────────┘ └─────────────┘
^ │
│ pthread_cond_signal()/ │ pthread_cond_broadcast()
│ pthread_cond_broadcast() │
└──────────────────────────────────────┘
5.2.2 条件变量的超时与时钟选择
现代系统支持多种时钟源的条件变量等待,这在实时系统中尤为重要。
c
#include <pthread.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
// 获取不同时钟的当前时间
void get_timespec(clockid_t clock_id, struct timespec *ts) {
if (clock_gettime(clock_id, ts) != 0) {
perror("clock_gettime");
ts->tv_sec = 0;
ts->tv_nsec = 0;
}
}
// 添加时间偏移
void add_timespec(struct timespec *ts, long seconds, long nanoseconds) {
ts->tv_sec += seconds;
ts->tv_nsec += nanoseconds;
if (ts->tv_nsec >= 1000000000L) {
ts->tv_sec += ts->tv_nsec / 1000000000L;
ts->tv_nsec %= 1000000000L;
}
}
void demonstrate_condition_timeouts() {
pthread_cond_t cond;
pthread_mutex_t mutex;
pthread_condattr_t cond_attr;
pthread_condattr_init(&cond_attr);
pthread_mutex_init(&mutex, NULL);
// 设置使用单调时钟(不受系统时间调整影响)
#ifdef _POSIX_CLOCK_SELECTION
pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
#endif
pthread_cond_init(&cond, &cond_attr);
pthread_mutex_lock(&mutex);
struct timespec timeout;
// 使用相对超时(3秒后)
#ifdef _POSIX_CLOCK_SELECTION
get_timespec(CLOCK_MONOTONIC, &timeout);
#else
get_timespec(CLOCK_REALTIME, &timeout);
#endif
add_timespec(&timeout, 3, 0); // 3秒超时
printf("开始条件变量等待,超时时间: %ld秒\n", timeout.tv_sec);
int result;
#ifdef _POSIX_CLOCK_SELECTION
result = pthread_cond_clockwait(&cond, &mutex, CLOCK_MONOTONIC, &timeout);
#else
result = pthread_cond_timedwait(&cond, &mutex, &timeout);
#endif
if (result == ETIMEDOUT) {
printf("条件变量等待超时\n");
} else if (result == 0) {
printf("条件变量被唤醒\n");
} else {
printf("条件变量等待错误: %s\n", strerror(result));
}
pthread_mutex_unlock(&mutex);
// 清理资源
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
pthread_condattr_destroy(&cond_attr);
}
int main() {
printf("条件变量超时演示开始\n");
demonstrate_condition_timeouts();
printf("条件变量超时演示结束\n");
return 0;
}
5.2.3 条件变量的虚假唤醒与处理策略
虚假唤醒(Spurious Wakeup)是条件变量编程中必须处理的重要问题。
c
#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>
// 线程安全的条件变量包装器
typedef struct {
pthread_cond_t cond;
pthread_mutex_t mutex;
bool condition_met;
int waiters;
} safe_condition_t;
void safe_condition_init(safe_condition_t *sc) {
pthread_cond_init(&sc->cond, NULL);
pthread_mutex_init(&sc->mutex, NULL);
sc->condition_met = false;
sc->waiters = 0;
}
void safe_condition_wait(safe_condition_t *sc, bool (*condition_check)(void*), void *arg) {
pthread_mutex_lock(&sc->mutex);
sc->waiters++;
// 必须使用while循环检查条件,防止虚假唤醒
while (!condition_check(arg) && !sc->condition_met) {
printf("线程 %lu: 进入等待,当前等待者: %d\n",
(unsigned long)pthread_self(), sc->waiters);
pthread_cond_wait(&sc->cond, &sc->mutex);
printf("线程 %lu: 被唤醒,重新检查条件\n",
(unsigned long)pthread_self());
}
sc->waiters--;
pthread_mutex_unlock(&sc->mutex);
}
void safe_condition_signal(safe_condition_t *sc) {
pthread_mutex_lock(&sc->mutex);
sc->condition_met = true;
printf("发送信号,唤醒一个等待者\n");
pthread_cond_signal(&sc->cond);
pthread_mutex_unlock(&sc->mutex);
}
void safe_condition_broadcast(safe_condition_t *sc) {
pthread_mutex_lock(&sc->mutex);
sc->condition_met = true;
printf("广播信号,唤醒所有等待者 (%d个)\n", sc->waiters);
pthread_cond_broadcast(&sc->cond);
pthread_mutex_unlock(&sc->mutex);
}
// 示例条件检查函数
bool global_condition_check(void *arg) {
int *value = (int*)arg;
return (*value >= 10);
}
// 测试线程函数
void* test_thread(void *arg) {
safe_condition_t *sc = (safe_condition_t*)arg;
static int counter = 0;
safe_condition_wait(sc, global_condition_check, &counter);
printf("线程 %lu: 条件满足,继续执行\n", (unsigned long)pthread_self());
return NULL;
}
int main() {
safe_condition_t sc;
safe_condition_init(&sc);
pthread_t threads[3];
printf("创建3个测试线程...\n");
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, test_thread, &sc);
}
// 模拟一些工作
sleep(2);
printf("主线程: 发送广播信号\n");
safe_condition_broadcast(&sc);
// 等待所有线程完成
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
printf("所有线程完成\n");
return 0;
}
5.3 读写锁的深入分析与性能优化
5.3.1 读写锁的内部实现机制
读写锁(Read-Write Lock)允许多个读操作并发执行,但写操作需要独占访问。
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 读写锁状态分析
void analyze_rwlock_state(pthread_rwlock_t *rwlock) {
// 注意:这只是一个演示,实际实现可能不同
printf("读写锁大小: %zu 字节\n", sizeof(*rwlock));
// 尝试获取读锁来分析状态
int result = pthread_rwlock_tryrdlock(rwlock);
if (result == 0) {
printf("状态: 可以获取读锁(无写锁持有)\n");
pthread_rwlock_unlock(rwlock);
} else if (result == EBUSY) {
printf("状态: 有写锁持有或写锁等待\n");
}
result = pthread_rwlock_trywrlock(rwlock);
if (result == 0) {
printf("状态: 可以获取写锁(完全空闲)\n");
pthread_rwlock_unlock(rwlock);
} else if (result == EBUSY) {
printf("状态: 有读锁或写锁持有\n");
}
}
// 读写锁性能测试
void* reader_thread(void *arg) {
pthread_rwlock_t *rwlock = (pthread_rwlock_t*)arg;
int reads_completed = 0;
for (int i = 0; i < 1000; i++) {
pthread_rwlock_rdlock(rwlock);
// 模拟读操作
usleep(100); // 100微秒
pthread_rwlock_unlock(rwlock);
reads_completed++;
}
printf("读线程 %lu: 完成 %d 次读操作\n",
(unsigned long)pthread_self(), reads_completed);
return NULL;
}
void* writer_thread(void *arg) {
pthread_rwlock_t *rwlock = (pthread_rwlock_t*)arg;
int writes_completed = 0;
for (int i = 0; i < 100; i++) {
pthread_rwlock_wrlock(rwlock);
// 模拟写操作
usleep(1000); // 1毫秒
pthread_rwlock_unlock(rwlock);
writes_completed++;
}
printf("写线程 %lu: 完成 %d 次写操作\n",
(unsigned long)pthread_self(), writes_completed);
return NULL;
}
void performance_test() {
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
pthread_t readers[5], writers[2];
printf("开始读写锁性能测试...\n");
// 创建读线程
for (int i = 0; i < 5; i++) {
pthread_create(&readers[i], NULL, reader_thread, &rwlock);
}
// 创建写线程
for (int i = 0; i < 2; i++) {
pthread_create(&writers[i], NULL, writer_thread, &rwlock);
}
// 等待所有线程完成
for (int i = 0; i < 5; i++) {
pthread_join(readers[i], NULL);
}
for (int i = 0; i < 2; i++) {
pthread_join(writers[i], NULL);
}
pthread_rwlock_destroy(&rwlock);
printf("性能测试完成\n");
}
int main() {
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
printf("=== 读写锁分析 ===\n");
analyze_rwlock_state(&rwlock);
printf("\n=== 性能测试 ===\n");
performance_test();
pthread_rwlock_destroy(&rwlock);
return 0;
}
5.3.2 读写锁的优先级策略
不同的读写锁实现支持不同的优先级策略,影响读线程和写线程的调度。
c
#include <pthread.h>
#include <stdio.h>
void demonstrate_rwlock_preferences() {
pthread_rwlock_t rwlock;
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
// 测试不同的优先级策略
int preferences[] = {
PTHREAD_RWLOCK_PREFER_READER_NP, // 偏向读者
PTHREAD_RWLOCK_PREFER_WRITER_NP, // 偏向写者
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP // 偏向非递归写者
};
const char *preference_names[] = {
"读者优先",
"写者优先",
"非递归写者优先"
};
for (int i = 0; i < 3; i++) {
printf("\n=== 测试策略: %s ===\n", preference_names[i]);
pthread_rwlockattr_setkind_np(&attr, preferences[i]);
pthread_rwlock_init(&rwlock, &attr);
// 获取当前设置的策略
int current_pref;
pthread_rwlockattr_getkind_np(&attr, ¤t_pref);
printf("当前策略代码: %d\n", current_pref);
pthread_rwlock_destroy(&rwlock);
}
pthread_rwlockattr_destroy(&attr);
}
// 读者优先 vs 写者优先的性能影响分析
void analyze_preference_impact() {
printf("\n=== 优先级策略性能影响分析 ===\n");
printf("1. 读者优先 (PTHREAD_RWLOCK_PREFER_READER_NP):\n");
printf(" - 优点: 读吞吐量高\n");
printf(" - 缺点: 写者可能饥饿\n");
printf(" - 适用: 读多写少的场景\n\n");
printf("2. 写者优先 (PTHREAD_RWLOCK_PREFER_WRITER_NP):\n");
printf(" - 优点: 写操作响应快\n");
printf(" - 缺点: 读者可能饥饿\n");
printf(" - 适用: 写操作重要的场景\n\n");
printf("3. 非递归写者优先 (PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP):\n");
printf(" - 优点: 避免写者饥饿的公平策略\n");
printf(" - 缺点: 实现复杂度高\n");
printf(" - 适用: 需要公平性的场景\n");
}
int main() {
demonstrate_rwlock_preferences();
analyze_preference_impact();
return 0;
}
5.4 自旋锁与适应性互斥锁
5.4.1 自旋锁的实现与适用场景
自旋锁(Spinlock)在短时间内避免上下文切换,适用于多核系统中的短临界区保护。
c
#include <pthread.h>
#include <stdio.h>
#include <sched.h>
// 自定义自旋锁实现(教育目的)
typedef struct {
volatile int lock;
} custom_spinlock_t;
void custom_spin_init(custom_spinlock_t *spinlock) {
spinlock->lock = 0;
}
void custom_spin_lock(custom_spinlock_t *spinlock) {
while (__sync_lock_test_and_set(&spinlock->lock, 1)) {
// 自旋等待,但要让出CPU避免过度占用
while (spinlock->lock) {
// 使用CPU暂停指令减少功耗(如果可用)
#ifdef __x86_64__
asm volatile("pause" ::: "memory");
#endif
// 短暂让出CPU
sched_yield();
}
}
}
void custom_spin_unlock(custom_spinlock_t *spinlock) {
__sync_lock_release(&spinlock->lock);
}
// 性能对比:自旋锁 vs 互斥锁
#include <time.h>
void benchmark_spinlock_vs_mutex() {
const int ITERATIONS = 1000000;
struct timespec start, end;
// 测试自旋锁
pthread_spinlock_t spinlock;
pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < ITERATIONS; i++) {
pthread_spin_lock(&spinlock);
// 极短临界区
pthread_spin_unlock(&spinlock);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long spin_time = (end.tv_sec - start.tv_sec) * 1000000000L +
(end.tv_nsec - start.tv_nsec);
// 测试互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < ITERATIONS; i++) {
pthread_mutex_lock(&mutex);
// 极短临界区
pthread_mutex_unlock(&mutex);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long mutex_time = (end.tv_sec - start.tv_sec) * 1000000000L +
(end.tv_nsec - start.tv_nsec);
printf("性能对比结果:\n");
printf("自旋锁: %ld 纳秒 (%d 次操作)\n", spin_time, ITERATIONS);
printf("互斥锁: %ld 纳秒 (%d 次操作)\n", mutex_time, ITERATIONS);
printf("自旋锁/互斥锁时间比: %.2f\n", (double)spin_time / mutex_time);
pthread_spin_destroy(&spinlock);
pthread_mutex_destroy(&mutex);
}
int main() {
printf("=== 自旋锁演示 ===\n");
custom_spinlock_t spinlock;
custom_spin_init(&spinlock);
printf("自定义自旋锁测试...\n");
custom_spin_lock(&spinlock);
printf("自旋锁已获取\n");
custom_spin_unlock(&spinlock);
printf("自旋锁已释放\n");
printf("\n=== 性能对比测试 ===\n");
benchmark_spinlock_vs_mutex();
return 0;
}
5.4.2 适应性互斥锁的工作原理
适应性互斥锁(Adaptive Mutex)结合了自旋锁和传统互斥锁的优点,根据临界区长度动态选择策略。
c
#include <pthread.h>
#include <stdio.h>
#include <time.h>
// 适应性锁策略分析
void analyze_adaptive_behavior() {
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
pthread_mutex_init(&mutex, &attr);
printf("适应性互斥锁特性分析:\n");
printf("1. 短临界区: 采用自旋等待,避免上下文切换\n");
printf("2. 长临界区: 切换到阻塞等待,释放CPU\n");
printf("3. 自适应: 根据历史等待时间调整策略\n");
// 测试短临界区(预期使用自旋)
struct timespec short_start, short_end;
clock_gettime(CLOCK_MONOTONIC, &short_start);
for (int i = 0; i < 1000; i++) {
pthread_mutex_lock(&mutex);
// 极短工作 - 几个纳秒
pthread_mutex_unlock(&mutex);
}
clock_gettime(CLOCK_MONOTONIC, &short_end);
long short_time = (short_end.tv_sec - short_start.tv_sec) * 1000000000L +
(short_end.tv_nsec - short_start.tv_nsec);
// 测试长临界区(预期使用阻塞)
clock_gettime(CLOCK_MONOTONIC, &short_start);
for (int i = 0; i < 10; i++) {
pthread_mutex_lock(&mutex);
// 较长工作 - 1毫秒
struct timespec sleep_time = {0, 1000000}; // 1毫秒
nanosleep(&sleep_time, NULL);
pthread_mutex_unlock(&mutex);
}
clock_gettime(CLOCK_MONOTONIC, &short_end);
long long_time = (short_end.tv_sec - short_start.tv_sec) * 1000000000L +
(short_end.tv_nsec - short_start.tv_nsec);
printf("\n性能数据:\n");
printf("短临界区(1000次): %ld 纳秒\n", short_time);
printf("长临界区(10次): %ld 纳秒\n", long_time);
printf("平均每次短操作: %ld 纳秒\n", short_time / 1000);
printf("平均每次长操作: %ld 纳秒\n", long_time / 10);
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&attr);
}
// 适应性锁 vs 其他锁类型对比
void compare_mutex_types() {
printf("\n=== 互斥锁类型对比 ===\n");
int mutex_types[] = {
PTHREAD_MUTEX_NORMAL,
PTHREAD_MUTEX_RECURSIVE,
PTHREAD_MUTEX_ERRORCHECK,
PTHREAD_MUTEX_ADAPTIVE_NP
};
const char *type_names[] = {
"普通锁",
"递归锁",
"错误检查锁",
"适应性锁"
};
for (int i = 0; i < 4; i++) {
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, mutex_types[i]);
if (pthread_mutex_init(&mutex, &attr) == 0) {
printf("%s: 初始化成功\n", type_names[i]);
pthread_mutex_destroy(&mutex);
} else {
printf("%s: 初始化失败\n", type_names[i]);
}
pthread_mutexattr_destroy(&attr);
}
}
int main() {
printf("适应性互斥锁深入分析\n");
analyze_adaptive_behavior();
compare_mutex_types();
return 0;
}
第六章:线程安全与可重入编程
6.1 线程安全函数的设计原则
6.1.1 可重入函数与线程安全函数的区别
理解可重入(Reentrant)和线程安全(Thread-safe)的区别对于编写高质量的多线程代码至关重要。
c
#include <pthread.h>
#include <stdio.h>
#include <string.h>
// 非线程安全的函数示例
static char buffer[100];
char* unsafe_greeting(const char *name) {
// 使用静态缓冲区 - 非线程安全
snprintf(buffer, sizeof(buffer), "Hello, %s!", name);
return buffer;
}
// 线程安全的可重入版本
char* safe_greeting(const char *name, char *buffer, size_t size) {
// 使用调用者提供的缓冲区 - 线程安全且可重入
snprintf(buffer, size, "Hello, %s!", name);
return buffer;
}
// 测试函数
void* test_unsafe_thread(void *arg) {
int thread_id = *(int*)arg;
// 非线程安全版本的测试
char *result = unsafe_greeting("World");
printf("线程 %d: %s (地址: %p)\n", thread_id, result, (void*)result);
return NULL;
}
void* test_safe_thread(void *arg) {
int thread_id = *(int*)arg;
char local_buffer[100];
// 线程安全版本的测试
char *result = safe_greeting("World", local_buffer, sizeof(local_buffer));
printf("线程 %d: %s (地址: %p)\n", thread_id, result, (void*)result);
return NULL;
}
void demonstrate_safety_issues() {
pthread_t threads[3];
int thread_ids[3] = {1, 2, 3};
printf("=== 非线程安全函数测试 ===\n");
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, test_unsafe_thread, &thread_ids[i]);
}
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
printf("\n=== 线程安全函数测试 ===\n");
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, test_safe_thread, &thread_ids[i]);
}
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
}
// 可重入函数的设计模式
typedef struct {
int value;
pthread_mutex_t mutex;
} thread_safe_counter;
void counter_init(thread_safe_counter *counter) {
counter->value = 0;
pthread_mutex_init(&counter->mutex, NULL);
}
void counter_increment(thread_safe_counter *counter) {
pthread_mutex_lock(&counter->mutex);
counter->value++;
pthread_mutex_unlock(&counter->mutex);
}
int counter_get(thread_safe_counter *counter) {
pthread_mutex_lock(&counter->mutex);
int value = counter->value;
pthread_mutex_unlock(&counter->mutex);
return value;
}
void counter_destroy(thread_safe_counter *counter) {
pthread_mutex_destroy(&counter->mutex);
}
int main() {
printf("线程安全与可重入编程演示\n");
demonstrate_safety_issues();
// 线程安全计数器的使用示例
thread_safe_counter counter;
counter_init(&counter);
pthread_t threads[5];
for (int i = 0; i < 5; i++) {
pthread_create(&threads[i], NULL,
(void*(*)(void*))counter_increment, &counter);
}
for (int i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}
printf("最终计数值: %d\n", counter_get(&counter));
counter_destroy(&counter);
return 0;
}
6.1.2 线程局部存储的高级用法
线程局部存储(Thread-Local Storage, TLS)允许每个线程拥有变量的独立副本,是实现线程安全的重要工具。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// C11 线程局部存储关键字
_Thread_local int tls_var = 0;
// POSIX 线程特定数据
pthread_key_t tls_key;
void tls_destructor(void *value) {
printf("清理线程特定数据: %p\n", value);
free(value);
}
void init_tls() {
pthread_key_create(&tls_key, tls_destructor);
}
int* get_thread_specific_data() {
int *data = pthread_getspecific(tls_key);
if (data == NULL) {
data = malloc(sizeof(int));
*data = 0;
pthread_setspecific(tls_key, data);
printf("为线程 %lu 分配线程特定数据\n", (unsigned long)pthread_self());
}
return data;
}
void* tls_test_thread(void *arg) {
int thread_id = *(int*)arg;
// 使用 C11 _Thread_local
tls_var = thread_id * 10;
printf("线程 %d: C11 TLS 变量 = %d\n", thread_id, tls_var);
// 使用 POSIX 线程特定数据
int *data = get_thread_specific_data();
*data = thread_id * 100;
printf("线程 %d: POSIX TLS 数据 = %d\n", thread_id, *data);
return NULL;
}
void demonstrate_tls_performance() {
const int NUM_THREADS = 100;
const int NUM_ITERATIONS = 1000;
pthread_t threads[NUM_THREADS];
int thread_ids[NUM_THREADS];
init_tls();
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// 创建大量线程测试TLS性能
for (int i = 0; i < NUM_THREADS; i++) {
thread_ids[i] = i;
pthread_create(&threads[i], NULL, tls_test_thread, &thread_ids[i]);
}
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long time_taken = (end.tv_sec - start.tv_sec) * 1000000000L +
(end.tv_nsec - start.tv_nsec);
printf("TLS性能测试: %d个线程完成,总时间: %ld 纳秒\n",
NUM_THREADS, time_taken);
pthread_key_delete(tls_key);
}
// TLS在复杂数据结构中的应用
typedef struct {
int id;
char name[50];
double values[100];
} thread_context_t;
pthread_key_t context_key;
void context_destructor(void *value) {
thread_context_t *context = (thread_context_t*)value;
printf("清理线程上下文: %s (ID: %d)\n", context->name, context->id);
free(context);
}
void init_context_tls() {
pthread_key_create(&context_key, context_destructor);
}
thread_context_t* get_thread_context() {
thread_context_t *context = pthread_getspecific(context_key);
if (context == NULL) {
context = malloc(sizeof(thread_context_t));
context->id = (int)pthread_self() % 1000; // 简单ID生成
snprintf(context->name, sizeof(context->name), "Thread-%lu",
(unsigned long)pthread_self());
// 初始化数据
for (int i = 0; i < 100; i++) {
context->values[i] = (double)i * 1.5;
}
pthread_setspecific(context_key, context);
printf("创建线程上下文: %s\n", context->name);
}
return context;
}
void* complex_tls_thread(void *arg) {
thread_context_t *context = get_thread_context();
// 使用线程上下文
printf("线程 %s 开始工作,values[0] = %.2f\n",
context->name, context->values[0]);
// 修改上下文数据
for (int i = 0; i < 10; i++) {
context->values[i] *= 2.0;
}
printf("线程 %s 完成工作,values[0] = %.2f\n",
context->name, context->values[0]);
return NULL;
}
int main() {
printf("=== 线程局部存储高级用法演示 ===\n");
printf("\n1. 基础TLS性能测试:\n");
demonstrate_tls_performance();
printf("\n2. 复杂数据结构TLS应用:\n");
init_context_tls();
pthread_t threads[3];
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, complex_tls_thread, NULL);
}
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
pthread_key_delete(context_key);
return 0;
}
由于篇幅限制,先提供这两个章节的详细内容。这些内容涵盖了线程同步原语的高级特性和线程安全编程的核心概念,包含了详细的代码示例、原理分析和性能对比。
深入解析pthread.h:Linux多线程编程完全指南(第三部分)
第七章:线程取消机制与资源清理
7.1 线程取消的深入理解
7.1.1 取消点的详细分析
取消点是线程检查取消请求并可能终止的特殊位置。理解这些位置对于编写可靠的取消安全代码至关重要。
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
// 测试各种取消点的函数
void test_cancellation_points() {
printf("=== 取消点测试 ===\n");
// 1. 标准I/O函数 - 取消点
printf("测试标准I/O取消点...\n");
printf("这是一个潜在的取消点\n");
// 2. 文件I/O操作 - 取消点
printf("测试文件I/O取消点...\n");
int fd = open("/tmp/test_cancel", O_CREAT | O_RDWR, 0644);
if (fd >= 0) {
char buffer[100];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
printf("读取了 %zd 字节\n", bytes_read);
ssize_t bytes_written = write(fd, "test", 4);
printf("写入了 %zd 字节\n", bytes_written);
close(fd);
}
// 3. 进程控制 - 取消点
printf("测试进程控制取消点...\n");
pid_t pid = fork();
if (pid == 0) {
// 子进程
printf("子进程创建成功\n");
_exit(0);
} else if (pid > 0) {
// 父进程
waitpid(pid, NULL, 0);
}
// 4. 线程操作 - 取消点
printf("测试线程操作取消点...\n");
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
struct timespec timeout;
clock_gettime(CLOCK_REALTIME, &timeout);
timeout.tv_sec += 1; // 1秒超时
pthread_cond_timedwait(&cond, &mutex, &timeout);
pthread_mutex_unlock(&mutex);
printf("所有取消点测试完成\n");
}
// 手动取消点测试
void* cancellation_test_thread(void* arg) {
int thread_id = *(int*)arg;
printf("线程 %d: 开始执行\n", thread_id);
// 非取消点区域 - 不会被取消
for (int i = 0; i < 3; i++) {
printf("线程 %d: 计算中... %d\n", thread_id, i);
// 这里不是取消点,除非我们手动添加
}
// 手动添加取消点
printf("线程 %d: 添加手动取消点\n", thread_id);
pthread_testcancel();
// 取消点区域
printf("线程 %d: 进入取消点区域\n", thread_id);
sleep(2); // sleep是取消点
printf("线程 %d: 正常完成\n", thread_id);
return NULL;
}
void demonstrate_cancellation_points() {
pthread_t threads[3];
int thread_ids[3] = {1, 2, 3};
printf("创建3个测试线程...\n");
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, cancellation_test_thread, &thread_ids[i]);
}
// 给线程一些时间执行
usleep(500000); // 0.5秒
// 取消线程2
printf("取消线程2...\n");
pthread_cancel(threads[1]);
// 等待所有线程
for (int i = 0; i < 3; i++) {
void *result;
pthread_join(threads[i], &result);
if (result == PTHREAD_CANCELED) {
printf("线程 %d 被取消\n", i + 1);
} else {
printf("线程 %d 正常完成\n", i + 1);
}
}
}
int main() {
printf("线程取消机制深入分析\n");
// 测试各种取消点
test_cancellation_points();
printf("\n=== 取消点行为演示 ===\n");
demonstrate_cancellation_points();
return 0;
}
7.1.2 取消类型与状态的组合效应
线程取消的行为由取消状态和取消类型的组合决定,理解这些组合对于编写正确的取消安全代码至关重要。
c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 取消状态和类型组合测试
typedef struct {
int state; // 取消状态
int type; // 取消类型
const char* name;
} cancel_config_t;
void* test_cancel_config(void* arg) {
cancel_config_t* config = (cancel_config_t*)arg;
int old_state, old_type;
printf("线程 %s: 设置取消状态=%s, 类型=%s\n",
config->name,
config->state == PTHREAD_CANCEL_ENABLE ? "启用" : "禁用",
config->type == PTHREAD_CANCEL_DEFERRED ? "延迟" : "异步");
// 设置取消状态和类型
pthread_setcancelstate(config->state, &old_state);
pthread_setcanceltype(config->type, &old_type);
printf("线程 %s: 旧状态=%s, 旧类型=%s\n",
config->name,
old_state == PTHREAD_CANCEL_ENABLE ? "启用" : "禁用",
old_type == PTHREAD_CANCEL_DEFERRED ? "延迟" : "异步");
// 执行一些工作
for (int i = 0; i < 5; i++) {
printf("线程 %s: 工作循环 %d\n", config->name, i);
if (i == 2) {
printf("线程 %s: 在循环中间\n", config->name);
// 手动取消点
pthread_testcancel();
}
usleep(200000); // 200ms
}
printf("线程 %s: 正常完成\n", config->name);
return (void*)(long)config->name[0]; // 返回第一个字符作为标识
}
void analyze_cancel_combinations() {
pthread_t threads[4];
cancel_config_t configs[4] = {
{PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DEFERRED, "启用-延迟"},
{PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_ASYNCHRONOUS, "启用-异步"},
{PTHREAD_CANCEL_DISABLE, PTHREAD_CANCEL_DEFERRED, "禁用-延迟"},
{PTHREAD_CANCEL_DISABLE, PTHREAD_CANCEL_ASYNCHRONOUS, "禁用-异步"}
};
printf("=== 取消配置组合分析 ===\n");
// 创建测试线程
for (int i = 0; i < 4; i++) {
pthread_create(&threads[i], NULL, test_cancel_config, &configs[i]);
}
// 给线程一些时间开始执行
sleep(1);
// 取消所有线程
printf("\n主线程: 取消所有测试线程\n");
for (int i = 0; i < 4; i++) {
pthread_cancel(threads[i]);
}
// 等待线程结束并分析结果
for (int i = 0; i < 4; i++) {
void* result;
pthread_join(threads[i], &result);
if (result == PTHREAD_CANCELED) {
printf("线程 %s: 被取消\n", configs[i].name);
} else {
printf("线程 %s: 正常完成 (结果: %ld)\n",
configs[i].name, (long)result);
}
}
printf("\n=== 取消配置行为总结 ===\n");
printf("1. 启用-延迟: 只在取消点响应取消\n");
printf("2. 启用-异步: 任何时间点都可能被取消\n");
printf("3. 禁用-延迟: 忽略取消请求\n");
printf("4. 禁用-异步: 忽略取消请求\n");
}
// 异步取消的安全考虑
void* async_cancel_unsafe(void* arg) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
// 危险操作:可能在malloc中间被取消
printf("异步取消线程: 分配内存...\n");
char* buffer = malloc(1024);
if (buffer) {
// 可能在这里被取消,导致内存泄漏
strcpy(buffer, "Hello, World!");
printf("异步取消线程: %s\n", buffer);
free(buffer); // 可能永远不会执行
}
return NULL;
}
void* async_cancel_safe(void* arg) {
// 在关键区域禁用取消
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
printf("安全异步取消线程: 分配内存...\n");
char* buffer = malloc(1024);
if (buffer) {
strcpy(buffer, "Hello, Safe World!");
printf("安全异步取消线程: %s\n", buffer);
}
// 重新启用取消
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
// 现在可以安全取消了
pthread_testcancel();
if (buffer) {
free(buffer); // 确保释放内存
}
return NULL;
}
int main() {
printf("取消类型与状态组合分析\n");
analyze_cancel_combinations();
printf("\n=== 异步取消安全性演示 ===\n");
pthread_t unsafe_thread, safe_thread;
printf("创建不安全异步取消线程...\n");
pthread_create(&unsafe_thread, NULL, async_cancel_unsafe, NULL);
usleep(100000);
pthread_cancel(unsafe_thread);
pthread_join(unsafe_thread, NULL);
printf("不安全线程结束(可能内存泄漏)\n");
printf("创建安全异步取消线程...\n");
pthread_create(&safe_thread, NULL, async_cancel_safe, NULL);
usleep(100000);
pthread_cancel(safe_thread);
pthread_join(safe_thread, NULL);
printf("安全线程结束(无内存泄漏)\n");
return 0;
}
7.2 清理处理程序的复杂应用
7.2.1 多级清理处理程序
在复杂的多线程应用中,可能需要多级清理处理程序来正确处理资源释放。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 资源类型定义
typedef struct {
int id;
char name[50];
void* data;
} resource_t;
// 多级清理处理程序
void cleanup_level3(void* arg) {
resource_t* res = (resource_t*)arg;
printf("三级清理: 释放资源数据 %s (ID: %d)\n", res->name, res->id);
if (res->data) {
free(res->data);
res->data = NULL;
}
}
void cleanup_level2(void* arg) {
resource_t* res = (resource_t*)arg;
printf("二级清理: 关闭资源 %s (ID: %d)\n", res->name, res->id);
// 注册三级清理
pthread_cleanup_push(cleanup_level3, res);
pthread_cleanup_pop(1); // 立即执行三级清理
}
void cleanup_level1(void* arg) {
resource_t* res = (resource_t*)arg;
printf("一级清理: 资源 %s (ID: %d) 开始清理\n", res->name, res->id);
// 注册二级清理
pthread_cleanup_push(cleanup_level2, res);
pthread_cleanup_pop(1); // 立即执行二级清理
}
// 复杂资源分配函数
resource_t* allocate_complex_resource(int id, const char* name) {
resource_t* res = malloc(sizeof(resource_t));
if (res) {
res->id = id;
snprintf(res->name, sizeof(res->name), "%s", name);
res->data = malloc(100); // 分配一些数据
if (res->data) {
snprintf((char*)res->data, 100, "数据内容 %s", name);
}
printf("分配资源: %s (ID: %d)\n", res->name, res->id);
}
return res;
}
void complex_operation(resource_t* res1, resource_t* res2) {
// 注册一级清理处理程序
pthread_cleanup_push(cleanup_level1, res1);
pthread_cleanup_push(cleanup_level1, res2);
printf("执行复杂操作...\n");
// 模拟一些工作
for (int i = 0; i < 3; i++) {
printf("操作步骤 %d\n", i);
usleep(500000);
// 在某个步骤模拟错误,触发清理
if (i == 1) {
printf("模拟操作失败,触发清理\n");
pthread_exit(NULL); // 这会触发清理处理程序
}
}
printf("操作成功完成\n");
// 正常完成,不执行清理(参数为0)
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
}
void* complex_worker_thread(void* arg) {
int thread_id = *(int*)arg;
printf("线程 %d: 开始复杂工作\n", thread_id);
// 分配多个资源
resource_t* res1 = allocate_complex_resource(thread_id * 10 + 1, "资源A");
resource_t* res2 = allocate_complex_resource(thread_id * 10 + 2, "资源B");
if (!res1 || !res2) {
printf("线程 %d: 资源分配失败\n", thread_id);
if (res1) free(res1);
if (res2) free(res2);
return NULL;
}
// 执行复杂操作(带有清理处理程序)
complex_operation(res1, res2);
// 如果正常完成,手动释放资源
printf("线程 %d: 手动释放资源\n", thread_id);
cleanup_level1(res1);
cleanup_level1(res2);
free(res1);
free(res2);
printf("线程 %d: 工作完成\n", thread_id);
return NULL;
}
int main() {
printf("=== 多级清理处理程序演示 ===\n");
pthread_t thread;
int thread_id = 1;
pthread_create(&thread, NULL, complex_worker_thread, &thread_id);
// 等待线程完成
pthread_join(thread, NULL);
printf("主线程: 复杂工作演示完成\n");
return 0;
}
7.2.2 清理处理程序的异常安全
清理处理程序提供了类似C++ RAII的异常安全保证,确保资源在任何退出路径上都能被正确释放。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
// 异常安全的文件操作包装器
typedef struct {
FILE* file;
const char* filename;
} file_handle_t;
void file_cleanup(void* arg) {
file_handle_t* fh = (file_handle_t*)arg;
if (fh && fh->file) {
printf("清理: 关闭文件 %s\n", fh->filename);
fclose(fh->file);
fh->file = NULL;
}
}
// 异常安全的文件打开
FILE* safe_fopen(const char* filename, const char* mode, file_handle_t* fh) {
fh->filename = filename;
fh->file = fopen(filename, mode);
if (fh->file) {
printf("成功打开文件: %s\n", filename);
// 注册清理处理程序
pthread_cleanup_push(file_cleanup, fh);
} else {
printf("无法打开文件: %s\n", filename);
}
return fh->file;
}
// 异常安全的文件操作函数
void process_file_safely(const char* filename) {
file_handle_t fh = {NULL, filename};
int cleanup_needed = 0;
// 使用清理处理程序确保资源释放
if (safe_fopen(filename, "w", &fh)) {
cleanup_needed = 1;
pthread_cleanup_push(file_cleanup, &fh);
printf("开始处理文件...\n");
// 模拟可能失败的操作
for (int i = 0; i < 5; i++) {
printf("处理步骤 %d\n", i);
// 在步骤2模拟失败
if (i == 2) {
printf("模拟操作失败!\n");
pthread_exit(NULL); // 触发清理
}
// 写入文件
fprintf(fh.file, "数据行 %d\n", i);
}
printf("文件处理成功完成\n");
pthread_cleanup_pop(0); // 正常完成,不执行清理
cleanup_needed = 0;
}
// 如果正常完成,手动关闭文件
if (!cleanup_needed && fh.file) {
fclose(fh.file);
}
}
// 基于setjmp/longjmp的异常处理与清理处理程序的结合
static jmp_buf env;
void cleanup_with_longjmp(void* arg) {
printf("在longjmp前执行清理: %s\n", (char*)arg);
}
void* exception_safe_thread(void* arg) {
char* resource1 = "资源1";
char* resource2 = "资源2";
// 设置异常处理
if (setjmp(env) == 0) {
// 第一次执行,注册清理处理程序
pthread_cleanup_push(cleanup_with_longjmp, resource1);
pthread_cleanup_push(cleanup_with_longjmp, resource2);
printf("线程: 正常执行路径\n");
// 模拟一些工作
for (int i = 0; i < 3; i++) {
printf("工作步骤 %d\n", i);
// 在步骤1模拟严重错误
if (i == 1) {
printf遇到严重错误,执行longjmp!\n");
longjmp(env, 1); // 跳转到setjmp位置
}
}
printf("线程: 正常完成\n");
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
} else {
// longjmp后的恢复路径
printf("线程: 从异常中恢复\n");
// 注意:longjmp不会触发清理处理程序!
// 我们需要手动调用或使用其他机制
cleanup_with_longjmp(resource1);
cleanup_with_longjmp(resource2);
}
return NULL;
}
int main() {
printf("=== 异常安全与清理处理程序 ===\n");
printf("\n1. 文件操作异常安全演示:\n");
pthread_t file_thread;
pthread_create(&file_thread, NULL,
(void*(*)(void*))process_file_safely, "test_file.txt");
pthread_join(file_thread, NULL);
printf("\n2. setjmp/longjmp与清理处理程序:\n");
pthread_t exception_thread;
pthread_create(&exception_thread, NULL, exception_safe_thread, NULL);
pthread_join(exception_thread, NULL);
printf("\n=== 重要注意事项 ===\n");
printf("1. pthread_exit() 会触发清理处理程序\n");
printf("2. longjmp() 不会触发清理处理程序\n");
printf("3. return 不会触发清理处理程序\n");
printf("4. 正常完成时应使用pthread_cleanup_pop(0)\n");
return 0;
}
第八章:多线程调试与问题诊断
8.1 死锁检测与预防
8.1.1 死锁的自动检测机制
通过包装锁操作来检测潜在的死锁情况。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
// 线程安全的死锁检测器
typedef struct {
pthread_mutex_t mutex;
pthread_t* lock_owners;
pthread_mutex_t** owned_locks;
int max_locks;
} deadlock_detector_t;
deadlock_detector_t* detector_create(int max_locks) {
deadlock_detector_t* detector = malloc(sizeof(deadlock_detector_t));
detector->max_locks = max_locks;
detector->lock_owners = calloc(max_locks, sizeof(pthread_t));
detector->owned_locks = calloc(max_locks, sizeof(pthread_mutex_t*));
pthread_mutex_init(&detector->mutex, NULL);
return detector;
}
void detector_destroy(deadlock_detector_t* detector) {
pthread_mutex_destroy(&detector->mutex);
free(detector->lock_owners);
free(detector->owned_locks);
free(detector);
}
// 检查死锁的辅助函数
int detect_deadlock(deadlock_detector_t* detector, pthread_t thread, pthread_mutex_t* mutex) {
pthread_mutex_lock(&detector->mutex);
// 简化版的死锁检测:检查是否形成循环等待
for (int i = 0; i < detector->max_locks; i++) {
if (detector->owned_locks[i] == mutex) {
pthread_t owner = detector->lock_owners[i];
if (pthread_equal(owner, thread)) {
// 同一个线程重复获取锁 - 需要递归锁
pthread_mutex_unlock(&detector->mutex);
return -1; // 可能的设计错误
}
// 这里可以实现更复杂的循环检测
printf("警告: 线程 %lu 等待被线程 %lu 持有的锁 %p\n",
(unsigned long)thread, (unsigned long)owner, (void*)mutex);
}
}
pthread_mutex_unlock(&detector->mutex);
return 0;
}
// 安全的锁包装器
typedef struct {
pthread_mutex_t mutex;
deadlock_detector_t* detector;
const char* name;
} safe_mutex_t;
void safe_mutex_init(safe_mutex_t* sm, deadlock_detector_t* detector, const char* name) {
pthread_mutex_init(&sm->mutex, NULL);
sm->detector = detector;
sm->name = name;
}
void safe_mutex_lock(safe_mutex_t* sm) {
pthread_t self = pthread_self();
// 死锁检测
if (detect_deadlock(sm->detector, self, &sm->mutex) != 0) {
printf("潜在死锁检测: 线程 %lu 尝试获取 %s\n",
(unsigned long)self, sm->name);
}
printf("线程 %lu: 等待锁 %s\n", (unsigned long)self, sm->name);
pthread_mutex_lock(&sm->mutex);
printf("线程 %lu: 获得锁 %s\n", (unsigned long)self, sm->name);
// 记录锁的所有权
pthread_mutex_lock(&sm->detector->mutex);
for (int i = 0; i < sm->detector->max_locks; i++) {
if (sm->detector->owned_locks[i] == NULL) {
sm->detector->owned_locks[i] = &sm->mutex;
sm->detector->lock_owners[i] = self;
break;
}
}
pthread_mutex_unlock(&sm->detector->mutex);
}
void safe_mutex_unlock(safe_mutex_t* sm) {
pthread_t self = pthread_self();
printf("线程 %lu: 释放锁 %s\n", (unsigned long)self, sm->name);
// 清除锁的所有权记录
pthread_mutex_lock(&sm->detector->mutex);
for (int i = 0; i < sm->detector->max_locks; i++) {
if (sm->detector->owned_locks[i] == &sm->mutex) {
sm->detector->owned_locks[i] = NULL;
break;
}
}
pthread_mutex_unlock(&sm->detector->mutex);
pthread_mutex_unlock(&sm->mutex);
}
// 死锁演示
safe_mutex_t mutex1, mutex2;
void* deadlock_thread1(void* arg) {
safe_mutex_lock(&mutex1);
usleep(100000); // 让另一个线程有机会获取第二个锁
safe_mutex_lock(&mutex2);
printf("线程1: 成功获取两个锁\n");
safe_mutex_unlock(&mutex2);
safe_mutex_unlock(&mutex1);
return NULL;
}
void* deadlock_thread2(void* arg) {
safe_mutex_lock(&mutex2);
usleep(100000); // 让另一个线程有机会获取第一个锁
safe_mutex_lock(&mutex1);
printf("线程2: 成功获取两个锁\n");
safe_mutex_unlock(&mutex1);
safe_mutex_unlock(&mutex2);
return NULL;
}
void demonstrate_deadlock_detection() {
deadlock_detector_t* detector = detector_create(10);
safe_mutex_init(&mutex1, detector, "互斥锁1");
safe_mutex_init(&mutex2, detector, "互斥锁2");
pthread_t t1, t2;
printf("=== 死锁检测演示 ===\n");
printf("注意: 这可能会产生死锁,但检测器会发出警告\n");
pthread_create(&t1, NULL, deadlock_thread1, NULL);
pthread_create(&t2, NULL, deadlock_thread2, NULL);
// 等待一段时间看是否发生死锁
sleep(3);
printf("主线程: 尝试取消死锁线程\n");
pthread_cancel(t1);
pthread_cancel(t2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
detector_destroy(detector);
printf("死锁演示结束\n");
}
int main() {
printf("多线程死锁检测与预防\n");
demonstrate_deadlock_detection();
return 0;
}
8.1.2 锁层次结构与死锁预防
通过强制锁的获取顺序来预防死锁。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// 锁层次系统
typedef struct {
pthread_mutex_t mutex;
int level; // 层次级别,数字越小优先级越高
const char* name;
} hierarchical_mutex_t;
void hierarchical_mutex_init(hierarchical_mutex_t* hm, int level, const char* name) {
pthread_mutex_init(&hm->mutex, NULL);
hm->level = level;
hm->name = name;
}
// 线程局部存储记录当前持有的最高级别锁
static __thread int current_level = 0;
void hierarchical_mutex_lock(hierarchical_mutex_t* hm) {
if (hm->level >= current_level) {
printf("锁层次违规! 当前级别: %d, 尝试获取: %d (%s)\n",
current_level, hm->level, hm->name);
// 在实际系统中,这里应该抛出异常或采取其他措施
return;
}
printf("获取锁 %s (级别: %d)\n", hm->name, hm->level);
pthread_mutex_lock(&hm->mutex);
current_level = hm->level;
}
void hierarchical_mutex_unlock(hierarchical_mutex_t* hm) {
printf("释放锁 %s (级别: %d)\n", hm->name, hm->level);
current_level = 0; // 简化:重置级别
pthread_mutex_unlock(&hm->mutex);
}
// 锁层次演示
hierarchical_mutex_t high_level_mutex = {.level = 1, .name = "高级锁"};
hierarchical_mutex_t medium_level_mutex = {.level = 2, .name = "中级锁"};
hierarchical_mutex_t low_level_mutex = {.level = 3, .name = "低级锁"};
void* correct_lock_order_thread(void* arg) {
printf("正确锁顺序线程开始\n");
// 正确的顺序:从高级别到低级别
hierarchical_mutex_lock(&high_level_mutex);
hierarchical_mutex_lock(&medium_level_mutex);
hierarchical_mutex_lock(&low_level_mutex);
printf("正确顺序: 成功获取所有锁\n");
hierarchical_mutex_unlock(&low_level_mutex);
hierarchical_mutex_unlock(&medium_level_mutex);
hierarchical_mutex_unlock(&high_level_mutex);
return NULL;
}
void* incorrect_lock_order_thread(void* arg) {
printf("错误锁顺序线程开始\n");
// 错误的顺序:从低级别开始
hierarchical_mutex_lock(&low_level_mutex);
// 这里应该会失败,因为试图获取更高级别的锁
hierarchical_mutex_lock(&high_level_mutex);
printf("错误顺序: 这行不应该打印\n");
hierarchical_mutex_unlock(&high_level_mutex);
hierarchical_mutex_unlock(&low_level_mutex);
return NULL;
}
void demonstrate_lock_hierarchy() {
hierarchical_mutex_init(&high_level_mutex, 1, "高级锁");
hierarchical_mutex_init(&medium_level_mutex, 2, "中级锁");
hierarchical_mutex_init(&low_level_mutex, 3, "低级锁");
pthread_t correct_thread, incorrect_thread;
printf("=== 锁层次结构演示 ===\n");
printf("\n1. 正确锁顺序测试:\n");
pthread_create(&correct_thread, NULL, correct_lock_order_thread, NULL);
pthread_join(correct_thread, NULL);
printf("\n2. 错误锁顺序测试:\n");
pthread_create(&incorrect_thread, NULL, incorrect_lock_order_thread, NULL);
pthread_join(incorrect_thread, NULL);
printf("\n锁层次演示完成\n");
}
int main() {
printf("锁层次结构与死锁预防\n");
demonstrate_lock_hierarchy();
return 0;
}
8.2 性能分析与优化
8.2.1 锁竞争分析
分析多线程程序中的锁竞争情况,识别性能瓶颈。
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/sysinfo.h>
// 锁性能分析器
typedef struct {
pthread_mutex_t mutex;
long long lock_attempts;
long long lock_successes;
long long total_wait_time; // 纳秒
struct timespec last_lock_time;
} lock_profiler_t;
void profiler_init(lock_profiler_t* profiler) {
pthread_mutex_init(&profiler->mutex, NULL);
profiler->lock_attempts = 0;
profiler->lock_successes = 0;
profiler->total_wait_time = 0;
}
void profiler_record_lock_attempt(lock_profiler_t* profiler) {
__sync_fetch_and_add(&profiler->lock_attempts, 1);
}
void profiler_record_lock_success(lock_profiler_t* profiler, long long wait_time) {
__sync_fetch_and_add(&profiler->lock_successes, 1);
__sync_fetch_and_add(&profiler->total_wait_time, wait_time);
}
void profiler_report(lock_profiler_t* profiler, const char* lock_name) {
printf("=== 锁性能报告: %s ===\n", lock_name);
printf("锁尝试次数: %lld\n", profiler->lock_attempts);
printf("锁成功次数: %lld\n", profiler->lock_successes);
printf("总等待时间: %lld 纳秒\n", profiler->total_wait_time);
if (profiler->lock_successes > 0) {
printf("平均等待时间: %lld 纳秒\n",
profiler->total_wait_time / profiler->lock_successes);
}
double success_rate = (double)profiler->lock_successes / profiler->lock_attempts * 100;
printf("锁成功率: %.2f%%\n", success_rate);
if (success_rate < 80.0) {
printf("警告: 锁竞争激烈!\n");
}
}
// 带分析的锁
typedef struct {
pthread_mutex_t mutex;
lock_profiler_t profiler;
const char* name;
} analyzed_mutex_t;
void analyzed_mutex_init(analyzed_mutex_t* am, const char* name) {
pthread_mutex_init(&am->mutex, NULL);
profiler_init(&am->profiler);
am->name = name;
}
void analyzed_mutex_lock(analyzed_mutex_t* am) {
profiler_record_lock_attempt(&am->profiler);
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
pthread_mutex_lock(&am->mutex);
clock_gettime(CLOCK_MONOTONIC, &end);
long long wait_time = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
profiler_record_lock_success(&am->profiler, wait_time);
}
void analyzed_mutex_unlock(analyzed_mutex_t* am) {
pthread_mutex_unlock(&am->mutex);
}
void analyzed_mutex_report(analyzed_mutex_t* am) {
profiler_report(&am->profiler, am->name);
}
// 性能测试
analyzed_mutex_t test_mutex = {.name = "测试锁"};
const int NUM_OPERATIONS = 100000;
const int NUM_THREADS = 4;
void* performance_worker(void* arg) {
int thread_id = *(int*)arg;
for (int i = 0; i < NUM_OPERATIONS; i++) {
analyzed_mutex_lock(&test_mutex);
// 模拟一些工作
int result = 0;
for (int j = 0; j < 100; j++) {
result += j * j;
}
analyzed_mutex_unlock(&test_mutex);
}
printf("线程 %d 完成\n", thread_id);
return NULL;
}
void run_performance_test() {
analyzed_mutex_init(&test_mutex, "测试锁");
pthread_t threads[NUM_THREADS];
int thread_ids[NUM_THREADS];
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// 创建并启动工作线程
for (int i = 0; i < NUM_THREADS; i++) {
thread_ids[i] = i;
pthread_create(&threads[i], NULL, performance_worker, &thread_ids[i]);
}
// 等待所有线程完成
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long long total_time = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf("\n=== 性能测试结果 ===\n");
printf("总操作数: %d\n", NUM_OPERATIONS * NUM_THREADS);
printf("总时间: %lld 纳秒\n", total_time);
printf("吞吐量: %.2f 操作/秒\n",
(double)(NUM_OPERATIONS * NUM_THREADS) / total_time * 1e9);
analyzed_mutex_report(&test_mutex);
}
int main() {
printf("多线程性能分析与锁竞争检测\n");
run_performance_test();
return 0;
}
由于篇幅限制,先提供第七、八章的详细内容。这些章节涵盖了线程取消机制、资源清理、死锁检测和性能分析等高级主题,包含了实用的代码示例和深入的技术分析。
深入解析pthread.h:Linux多线程编程完全指南(第四部分)
第九章:高级多线程编程模式
9.1 线程池的高级实现与性能优化
9.1.1 高性能线程池设计
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
// 任务结构
typedef struct task {
void (*function)(void *arg);
void *arg;
struct task *next;
long long enqueue_time; // 入队时间(性能分析)
} task_t;
// 线程池统计信息
typedef struct {
long long tasks_completed;
long long total_wait_time; // 总等待时间(纳秒)
long long total_exec_time; // 总执行时间(纳秒)
long long max_wait_time;
long long max_exec_time;
} pool_stats_t;
// 高性能线程池
typedef struct {
// 任务队列
task_t *queue_head;
task_t *queue_tail;
int queue_size;
int queue_capacity;
// 线程管理
pthread_t *threads;
int thread_count;
int active_threads;
// 同步原语
pthread_mutex_t queue_mutex;
pthread_cond_t queue_not_empty;
pthread_cond_t queue_not_full;
pthread_cond_t all_tasks_done;
// 控制标志
int shutdown;
int drain; // 排空模式:不接受新任务,只处理现有任务
// 统计信息
pool_stats_t stats;
pthread_mutex_t stats_mutex;
// 性能优化
int use_spinlock; // 对短任务使用自旋锁
} thread_pool_t;
// 创建线程池
thread_pool_t* thread_pool_create(int thread_count, int queue_capacity, int use_spinlock) {
if (thread_count <= 0 || queue_capacity <= 0) {
return NULL;
}
thread_pool_t *pool = malloc(sizeof(thread_pool_t));
if (!pool) return NULL;
// 初始化基础字段
pool->queue_head = pool->queue_tail = NULL;
pool->queue_size = 0;
pool->queue_capacity = queue_capacity;
pool->thread_count = thread_count;
pool->active_threads = 0;
pool->shutdown = 0;
pool->drain = 0;
pool->use_spinlock = use_spinlock;
// 初始化统计信息
memset(&pool->stats, 0, sizeof(pool_stats_t));
// 初始化同步原语
if (pthread_mutex_init(&pool->queue_mutex, NULL) != 0) {
free(pool);
return NULL;
}
if (pthread_cond_init(&pool->queue_not_empty, NULL) != 0 ||
pthread_cond_init(&pool->queue_not_full, NULL) != 0 ||
pthread_cond_init(&pool->all_tasks_done, NULL) != 0) {
pthread_mutex_destroy(&pool->queue_mutex);
free(pool);
return NULL;
}
if (pthread_mutex_init(&pool->stats_mutex, NULL) != 0) {
pthread_mutex_destroy(&pool->queue_mutex);
pthread_cond_destroy(&pool->queue_not_empty);
pthread_cond_destroy(&pool->queue_not_full);
pthread_cond_destroy(&pool->all_tasks_done);
free(pool);
return NULL;
}
// 创建工作线程
pool->threads = malloc(sizeof(pthread_t) * thread_count);
if (!pool->threads) {
thread_pool_destroy(pool, 0);
return NULL;
}
for (int i = 0; i < thread_count; i++) {
if (pthread_create(&pool->threads[i], NULL, worker_thread, pool) != 0) {
// 创建失败,销毁已创建的线程
pool->thread_count = i; // 更新为成功创建的线程数
thread_pool_destroy(pool, 0);
return NULL;
}
pool->active_threads++;
}
return pool;
}
// 工作线程函数
void* worker_thread(void *arg) {
thread_pool_t *pool = (thread_pool_t*)arg;
while (1) {
task_t *task = NULL;
struct timespec wait_start, wait_end, exec_start, exec_end;
// 获取当前时间(等待开始)
clock_gettime(CLOCK_MONOTONIC, &wait_start);
pthread_mutex_lock(&pool->queue_mutex);
// 等待任务或关闭信号
while (pool->queue_size == 0 && !pool->shutdown) {
pthread_cond_wait(&pool->queue_not_empty, &pool->queue_mutex);
}
// 检查关闭条件
if (pool->shutdown && (pool->drain ? pool->queue_size == 0 : 1)) {
pool->active_threads--;
if (pool->active_threads == 0) {
pthread_cond_broadcast(&pool->all_tasks_done);
}
pthread_mutex_unlock(&pool->queue_mutex);
break;
}
// 获取任务
task = pool->queue_head;
if (task) {
pool->queue_head = task->next;
pool->queue_size--;
if (pool->queue_size == 0) {
pool->queue_tail = NULL;
}
// 通知生产者队列有空位
if (pool->queue_size == pool->queue_capacity - 1) {
pthread_cond_broadcast(&pool->queue_not_full);
}
}
pthread_mutex_unlock(&pool->queue_mutex);
// 获取等待结束时间
clock_gettime(CLOCK_MONOTONIC, &wait_end);
if (task) {
// 计算等待时间
long long wait_time = (wait_end.tv_sec - wait_start.tv_sec) * 1000000000LL +
(wait_end.tv_nsec - wait_start.tv_nsec);
// 执行任务
clock_gettime(CLOCK_MONOTONIC, &exec_start);
task->function(task->arg);
clock_gettime(CLOCK_MONOTONIC, &exec_end);
// 计算执行时间
long long exec_time = (exec_end.tv_sec - exec_start.tv_sec) * 1000000000LL +
(exec_end.tv_nsec - exec_start.tv_nsec);
// 更新统计信息
pthread_mutex_lock(&pool->stats_mutex);
pool->stats.tasks_completed++;
pool->stats.total_wait_time += wait_time;
pool->stats.total_exec_time += exec_time;
if (wait_time > pool->stats.max_wait_time) {
pool->stats.max_wait_time = wait_time;
}
if (exec_time > pool->stats.max_exec_time) {
pool->stats.max_exec_time = exec_time;
}
pthread_mutex_unlock(&pool->stats_mutex);
free(task);
}
}
return NULL;
}
// 提交任务(带超时)
int thread_pool_submit(thread_pool_t *pool, void (*function)(void *), void *arg, long timeout_ms) {
if (!pool || !function || pool->drain) {
return -1;
}
struct timespec ts;
if (timeout_ms > 0) {
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += timeout_ms / 1000;
ts.tv_nsec += (timeout_ms % 1000) * 1000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
}
pthread_mutex_lock(&pool->queue_mutex);
// 等待队列有空位
while (pool->queue_size >= pool->queue_capacity && !pool->shutdown && !pool->drain) {
if (timeout_ms > 0) {
if (pthread_cond_timedwait(&pool->queue_not_full, &pool->queue_mutex, &ts) == ETIMEDOUT) {
pthread_mutex_unlock(&pool->queue_mutex);
return -2; // 超时
}
} else {
pthread_cond_wait(&pool->queue_not_full, &pool->queue_mutex);
}
}
if (pool->shutdown || pool->drain) {
pthread_mutex_unlock(&pool->queue_mutex);
return -1;
}
// 创建新任务
task_t *task = malloc(sizeof(task_t));
if (!task) {
pthread_mutex_unlock(&pool->queue_mutex);
return -3; // 内存不足
}
task->function = function;
task->arg = arg;
task->next = NULL;
clock_gettime(CLOCK_MONOTONIC, &task->enqueue_time);
// 添加到队列
if (pool->queue_tail) {
pool->queue_tail->next = task;
} else {
pool->queue_head = task;
}
pool->queue_tail = task;
pool->queue_size++;
// 通知工作线程
pthread_cond_signal(&pool->queue_not_empty);
pthread_mutex_unlock(&pool->queue_mutex);
return 0;
}
// 获取统计信息
void thread_pool_get_stats(thread_pool_t *pool, pool_stats_t *stats) {
if (!pool || !stats) return;
pthread_mutex_lock(&pool->stats_mutex);
memcpy(stats, &pool->stats, sizeof(pool_stats_t));
pthread_mutex_unlock(&pool->stats_mutex);
}
// 销毁线程池
void thread_pool_destroy(thread_pool_t *pool, int drain) {
if (!pool) return;
pthread_mutex_lock(&pool->queue_mutex);
if (drain) {
// 排空模式:处理完所有任务再关闭
pool->drain = 1;
while (pool->queue_size > 0) {
pthread_cond_wait(&pool->all_tasks_done, &pool->queue_mutex);
}
}
pool->shutdown = 1;
pthread_cond_broadcast(&pool->queue_not_empty);
pthread_cond_broadcast(&pool->queue_not_full);
pthread_mutex_unlock(&pool->queue_mutex);
// 等待所有线程退出
for (int i = 0; i < pool->thread_count; i++) {
pthread_join(pool->threads[i], NULL);
}
// 清理剩余任务
task_t *task = pool->queue_head;
while (task) {
task_t *next = task->next;
free(task);
task = next;
}
// 销毁同步原语
pthread_mutex_destroy(&pool->queue_mutex);
pthread_mutex_destroy(&pool->stats_mutex);
pthread_cond_destroy(&pool->queue_not_empty);
pthread_cond_destroy(&pool->queue_not_full);
pthread_cond_destroy(&pool->all_tasks_done);
// 释放内存
free(pool->threads);
free(pool);
}
9.1.2 线程池性能测试与优化
c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 测试任务:矩阵乘法
typedef struct {
int size;
double **a, **b, **result;
int start_row, end_row;
} matrix_task_t;
void matrix_multiply_task(void *arg) {
matrix_task_t *task = (matrix_task_t*)arg;
for (int i = task->start_row; i < task->end_row; i++) {
for (int j = 0; j < task->size; j++) {
task->result[i][j] = 0;
for (int k = 0; k < task->size; k++) {
task->result[i][j] += task->a[i][k] * task->b[k][j];
}
}
}
free(task);
}
// 创建测试矩阵
double** create_matrix(int size) {
double **matrix = malloc(size * sizeof(double*));
for (int i = 0; i < size; i++) {
matrix[i] = malloc(size * sizeof(double));
for (int j = 0; j < size; j++) {
matrix[i][j] = (double)rand() / RAND_MAX;
}
}
return matrix;
}
void free_matrix(double **matrix, int size) {
for (int i = 0; i < size; i++) {
free(matrix[i]);
}
free(matrix);
}
// 性能测试函数
void performance_test() {
const int MATRIX_SIZE = 200;
const int NUM_TASKS = 8; // 将工作分成8个任务
const int THREAD_COUNTS[] = {1, 2, 4, 8};
const int NUM_TESTS = sizeof(THREAD_COUNTS) / sizeof(THREAD_COUNTS[0]);
printf("=== 线程池性能测试 ===\n");
printf("矩阵大小: %dx%d\n", MATRIX_SIZE, MATRIX_SIZE);
printf("任务数量: %d\n", NUM_TASKS);
// 创建测试数据
double **a = create_matrix(MATRIX_SIZE);
double **b = create_matrix(MATRIX_SIZE);
double **result = create_matrix(MATRIX_SIZE);
for (int test = 0; test < NUM_TESTS; test++) {
int thread_count = THREAD_COUNTS[test];
printf("\n测试 %d: %d 个线程\n", test + 1, thread_count);
thread_pool_t *pool = thread_pool_create(thread_count, NUM_TASKS, 0);
if (!pool) {
printf("创建线程池失败\n");
continue;
}
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// 提交任务
int rows_per_task = MATRIX_SIZE / NUM_TASKS;
for (int i = 0; i < NUM_TASKS; i++) {
matrix_task_t *task = malloc(sizeof(matrix_task_t));
task->size = MATRIX_SIZE;
task->a = a;
task->b = b;
task->result = result;
task->start_row = i * rows_per_task;
task->end_row = (i == NUM_TASKS - 1) ? MATRIX_SIZE : (i + 1) * rows_per_task;
if (thread_pool_submit(pool, matrix_multiply_task, task, 0) != 0) {
free(task);
printf("提交任务失败\n");
}
}
// 等待所有任务完成
thread_pool_destroy(pool, 1); // 排空模式关闭
clock_gettime(CLOCK_MONOTONIC, &end);
long long elapsed = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf("执行时间: %.3f 秒\n", elapsed / 1e9);
// 获取统计信息
pool_stats_t stats;
thread_pool_get_stats(pool, &stats);
printf("完成任务: %lld\n", stats.tasks_completed);
if (stats.tasks_completed > 0) {
printf("平均等待时间: %.3f 毫秒\n",
(stats.total_wait_time / stats.tasks_completed) / 1e6);
printf("平均执行时间: %.3f 毫秒\n",
(stats.total_exec_time / stats.tasks_completed) / 1e6);
}
}
// 清理
free_matrix(a, MATRIX_SIZE);
free_matrix(b, MATRIX_SIZE);
free_matrix(result, MATRIX_SIZE);
}
int main() {
printf("高级线程池性能测试\n");
performance_test();
return 0;
}
9.2 无锁编程与原子操作
9.2.1 原子操作的高级应用
c
#include <stdatomic.h>
#include <stdio.h>
#include <pthread.h>
#include <stdbool.h>
// 无锁栈实现
typedef struct lock_free_node {
void *data;
struct lock_free_node *next;
} lock_free_node_t;
typedef struct {
atomic_uintptr_t top; // 使用atomic_uintptr_t来保证原子性
atomic_size_t count;
} lock_free_stack_t;
void lock_free_stack_init(lock_free_stack_t *stack) {
atomic_store(&stack->top, (uintptr_t)NULL);
atomic_store(&stack->count, 0);
}
bool lock_free_stack_push(lock_free_stack_t *stack, void *data) {
lock_free_node_t *new_node = malloc(sizeof(lock_free_node_t));
if (!new_node) return false;
new_node->data = data;
uintptr_t current_top;
do {
current_top = atomic_load(&stack->top);
new_node->next = (lock_free_node_t*)current_top;
} while (!atomic_compare_exchange_weak(&stack->top, ¤t_top,
(uintptr_t)new_node));
atomic_fetch_add(&stack->count, 1);
return true;
}
void* lock_free_stack_pop(lock_free_stack_t *stack) {
uintptr_t current_top;
lock_free_node_t *next;
do {
current_top = atomic_load(&stack->top);
if (current_top == (uintptr_t)NULL) {
return NULL; // 栈为空
}
lock_free_node_t *current_node = (lock_free_node_t*)current_top;
next = current_node->next;
} while (!atomic_compare_exchange_weak(&stack->top, ¤t_top,
(uintptr_t)next));
lock_free_node_t *popped_node = (lock_free_node_t*)current_top;
void *data = popped_node->data;
free(popped_node);
atomic_fetch_sub(&stack->count, 1);
return data;
}
size_t lock_free_stack_size(lock_free_stack_t *stack) {
return atomic_load(&stack->count);
}
// 无锁队列实现(Michael-Scott算法)
typedef struct {
atomic_uintptr_t head;
atomic_uintptr_t tail;
atomic_size_t count;
} lock_free_queue_t;
typedef struct lf_queue_node {
void *data;
atomic_uintptr_t next;
} lf_queue_node_t;
void lock_free_queue_init(lock_free_queue_t *queue) {
lf_queue_node_t *dummy = malloc(sizeof(lf_queue_node_t));
dummy->data = NULL;
atomic_store(&dummy->next, (uintptr_t)NULL);
atomic_store(&queue->head, (uintptr_t)dummy);
atomic_store(&queue->tail, (uintptr_t)dummy);
atomic_store(&queue->count, 0);
}
bool lock_free_queue_enqueue(lock_free_queue_t *queue, void *data) {
lf_queue_node_t *new_node = malloc(sizeof(lf_queue_node_t));
if (!new_node) return false;
new_node->data = data;
atomic_store(&new_node->next, (uintptr_t)NULL);
uintptr_t tail, next;
while (1) {
tail = atomic_load(&queue->tail);
lf_queue_node_t *tail_node = (lf_queue_node_t*)tail;
next = atomic_load(&tail_node->next);
if (tail == atomic_load(&queue->tail)) {
if (next == (uintptr_t)NULL) {
if (atomic_compare_exchange_weak(&tail_node->next, &next,
(uintptr_t)new_node)) {
break;
}
} else {
atomic_compare_exchange_weak(&queue->tail, &tail, next);
}
}
}
atomic_compare_exchange_weak(&queue->tail, &tail, (uintptr_t)new_node);
atomic_fetch_add(&queue->count, 1);
return true;
}
void* lock_free_queue_dequeue(lock_free_queue_t *queue) {
uintptr_t head, tail, next;
void *data;
while (1) {
head = atomic_load(&queue->head);
tail = atomic_load(&queue->tail);
lf_queue_node_t *head_node = (lf_queue_node_t*)head;
next = atomic_load(&head_node->next);
if (head == atomic_load(&queue->head)) {
if (head == tail) {
if (next == (uintptr_t)NULL) {
return NULL; // 队列为空
}
atomic_compare_exchange_weak(&queue->tail, &tail, next);
} else {
data = ((lf_queue_node_t*)next)->data;
if (atomic_compare_exchange_weak(&queue->head, &head, next)) {
break;
}
}
}
}
free((lf_queue_node_t*)head);
atomic_fetch_sub(&queue->count, 1);
return data;
}
// 性能对比测试
void* stack_test_thread(void *arg) {
lock_free_stack_t *stack = (lock_free_stack_t*)arg;
for (int i = 0; i < 10000; i++) {
int *value = malloc(sizeof(int));
*value = i;
lock_free_stack_push(stack, value);
if (i % 2 == 0) {
void *popped = lock_free_stack_pop(stack);
if (popped) free(popped);
}
}
return NULL;
}
void performance_comparison() {
printf("=== 无锁数据结构性能测试 ===\n");
lock_free_stack_t stack;
lock_free_stack_init(&stack);
const int NUM_THREADS = 4;
pthread_t threads[NUM_THREADS];
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < NUM_THREADS; i++) {
pthread_create(&threads[i], NULL, stack_test_thread, &stack);
}
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
clock_gettime(CLOCK_MONOTONIC, &end);
long long elapsed = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf("无锁栈测试完成\n");
printf("线程数: %d\n", NUM_THREADS);
printf("总操作数: %d\n", NUM_THREADS * 10000);
printf("总时间: %.3f 秒\n", elapsed / 1e9);
printf("操作吞吐量: %.2f 操作/秒\n",
(NUM_THREADS * 10000.0) / (elapsed / 1e9));
printf("最终栈大小: %zu\n", lock_free_stack_size(&stack));
// 清理剩余节点
while (lock_free_stack_pop(&stack)) {
// 释放所有剩余节点
}
}
int main() {
printf("无锁编程与原子操作\n");
performance_comparison();
return 0;
}
第十章:实际项目案例研究
10.1 高性能网络服务器
10.1.1 Reactor模式网络服务器
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#define MAX_EVENTS 1024
#define BUFFER_SIZE 4096
#define MAX_CLIENTS 10000
// 客户端会话
typedef struct {
int fd;
struct sockaddr_in addr;
char read_buffer[BUFFER_SIZE];
int read_len;
char write_buffer[BUFFER_SIZE];
int write_len;
time_t last_activity;
} client_session_t;
// Reactor服务器
typedef struct {
int epoll_fd;
int listen_fd;
client_session_t *clients[MAX_CLIENTS];
pthread_mutex_t clients_mutex;
// 线程池
thread_pool_t *thread_pool;
// 统计信息
atomic_long total_connections;
atomic_long current_connections;
atomic_long total_requests;
} reactor_server_t;
// 设置非阻塞IO
int set_nonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) return -1;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
// 初始化服务器
reactor_server_t* server_create(int port, int thread_count) {
reactor_server_t *server = malloc(sizeof(reactor_server_t));
if (!server) return NULL;
memset(server, 0, sizeof(reactor_server_t));
// 创建epoll实例
server->epoll_fd = epoll_create1(0);
if (server->epoll_fd == -1) {
free(server);
return NULL;
}
// 创建监听socket
server->listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server->listen_fd == -1) {
close(server->epoll_fd);
free(server);
return NULL;
}
// 设置SO_REUSEADDR
int opt = 1;
setsockopt(server->listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 绑定地址
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(server->listen_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
close(server->listen_fd);
close(server->epoll_fd);
free(server);
return NULL;
}
// 开始监听
if (listen(server->listen_fd, SOMAXCONN) == -1) {
close(server->listen_fd);
close(server->epoll_fd);
free(server);
return NULL;
}
// 设置非阻塞
set_nonblocking(server->listen_fd);
// 添加监听socket到epoll
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET; // 边缘触发模式
ev.data.fd = server->listen_fd;
if (epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, server->listen_fd, &ev) == -1) {
close(server->listen_fd);
close(server->epoll_fd);
free(server);
return NULL;
}
// 初始化互斥锁
pthread_mutex_init(&server->clients_mutex, NULL);
// 创建线程池
server->thread_pool = thread_pool_create(thread_count, 1000, 0);
if (!server->thread_pool) {
close(server->listen_fd);
close(server->epoll_fd);
pthread_mutex_destroy(&server->clients_mutex);
free(server);
return NULL;
}
// 初始化原子变量
atomic_store(&server->total_connections, 0);
atomic_store(&server->current_connections, 0);
atomic_store(&server->total_requests, 0);
printf("服务器初始化完成,监听端口 %d\n", port);
return server;
}
// 处理HTTP请求的任务
typedef struct {
reactor_server_t *server;
client_session_t *session;
} http_task_t;
void http_request_handler(void *arg) {
http_task_t *task = (http_task_t*)arg;
client_session_t *session = task->session;
reactor_server_t *server = task->server;
// 简单的HTTP请求解析
char *request = session->read_buffer;
// 检查是否收到完整的HTTP请求(以\r\n\r\n结尾)
char *end_of_headers = strstr(request, "\r\n\r\n");
if (!end_of_headers) {
// 请求不完整,等待更多数据
free(task);
return;
}
// 解析请求行
char method[16], path[256], version[16];
sscanf(request, "%15s %255s %15s", method, path, version);
// 生成简单的HTTP响应
const char *response_template =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n"
"Connection: keep-alive\r\n"
"\r\n"
"Hello from reactor server! Path: %s";
char response_body[512];
snprintf(response_body, sizeof(response_body), "Hello from reactor server! Path: %s", path);
snprintf(session->write_buffer, sizeof(session->write_buffer),
response_template, strlen(response_body), path);
strcat(session->write_buffer, response_body);
session->write_len = strlen(session->write_buffer);
// 更新活动时间
session->last_activity = time(NULL);
// 更新统计信息
atomic_fetch_add(&server->total_requests, 1);
free(task);
}
// 接受新连接
void accept_connection(reactor_server_t *server) {
while (1) {
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int client_fd = accept(server->listen_fd,
(struct sockaddr*)&client_addr, &addr_len);
if (client_fd == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 没有更多连接了
break;
} else {
perror("accept");
break;
}
}
// 设置非阻塞
set_nonblocking(client_fd);
// 创建客户端会话
client_session_t *session = malloc(sizeof(client_session_t));
if (!session) {
close(client_fd);
continue;
}
memset(session, 0, sizeof(client_session_t));
session->fd = client_fd;
memcpy(&session->addr, &client_addr, sizeof(client_addr));
session->last_activity = time(NULL);
// 添加到客户端列表
pthread_mutex_lock(&server->clients_mutex);
int added = 0;
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] == NULL) {
server->clients[i] = session;
added = 1;
break;
}
}
pthread_mutex_unlock(&server->clients_mutex);
if (!added) {
// 达到最大客户端数
free(session);
close(client_fd);
continue;
}
// 添加到epoll
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
ev.data.ptr = session;
if (epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
perror("epoll_ctl add client");
pthread_mutex_lock(&server->clients_mutex);
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] == session) {
server->clients[i] = NULL;
break;
}
}
pthread_mutex_unlock(&server->clients_mutex);
free(session);
close(client_fd);
continue;
}
// 更新统计信息
atomic_fetch_add(&server->total_connections, 1);
atomic_fetch_add(&server->current_connections, 1);
printf("新连接: %s:%d (FD: %d)\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_fd);
}
}
// 处理客户端数据
void handle_client_data(reactor_server_t *server, client_session_t *session, uint32_t events) {
if (events & EPOLLRDHUP) {
// 连接关闭
printf("连接关闭: FD %d\n", session->fd);
goto close_connection;
}
if (events & EPOLLIN) {
// 读取数据
while (1) {
int n = read(session->fd,
session->read_buffer + session->read_len,
sizeof(session->read_buffer) - session->read_len - 1);
if (n > 0) {
session->read_len += n;
session->read_buffer[session->read_len] = '\0';
session->last_activity = time(NULL);
// 检查是否收到完整请求
if (strstr(session->read_buffer, "\r\n\r\n")) {
// 提交到线程池处理
http_task_t *task = malloc(sizeof(http_task_t));
task->server = server;
task->session = session;
if (thread_pool_submit(server->thread_pool, http_request_handler, task, 0) != 0) {
free(task);
}
}
} else if (n == 0) {
// 连接关闭
goto close_connection;
} else {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 没有更多数据了
break;
} else {
perror("read");
goto close_connection;
}
}
}
}
if (events & EPOLLOUT) {
// 写入数据
if (session->write_len > 0) {
int n = write(session->fd, session->write_buffer, session->write_len);
if (n > 0) {
// 移动剩余数据
memmove(session->write_buffer, session->write_buffer + n, session->write_len - n);
session->write_len -= n;
} else if (n == -1 && errno != EAGAIN) {
perror("write");
goto close_connection;
}
}
// 如果没有更多数据要写,停止监听写事件
if (session->write_len == 0) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
ev.data.ptr = session;
epoll_ctl(server->epoll_fd, EPOLL_CTL_MOD, session->fd, &ev);
}
}
return;
close_connection:
// 关闭连接
close(session->fd);
// 从epoll移除
epoll_ctl(server->epoll_fd, EPOLL_CTL_DEL, session->fd, NULL);
// 从客户端列表移除
pthread_mutex_lock(&server->clients_mutex);
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] == session) {
server->clients[i] = NULL;
break;
}
}
pthread_mutex_unlock(&server->clients_mutex);
atomic_fetch_sub(&server->current_connections, 1);
free(session);
}
// 服务器主循环
void server_run(reactor_server_t *server) {
struct epoll_event events[MAX_EVENTS];
printf("服务器开始运行...\n");
while (1) {
int nfds = epoll_wait(server->epoll_fd, events, MAX_EVENTS, 1000);
for (int i = 0; i < nfds; i++) {
if (events[i].data.fd == server->listen_fd) {
// 新连接
accept_connection(server);
} else {
// 客户端事件
client_session_t *session = (client_session_t*)events[i].data.ptr;
handle_client_data(server, session, events[i].events);
}
}
// 定期清理超时连接(简化版)
static time_t last_cleanup = 0;
time_t now = time(NULL);
if (now - last_cleanup > 30) { // 每30秒清理一次
// 这里可以实现连接超时清理
last_cleanup = now;
}
}
}
// 显示服务器状态
void server_status(reactor_server_t *server) {
printf("\n=== 服务器状态 ===\n");
printf("总连接数: %ld\n", atomic_load(&server->total_connections));
printf("当前连接数: %ld\n", atomic_load(&server->current_connections));
printf("总请求数: %ld\n", atomic_load(&server->total_requests));
// 线程池统计
pool_stats_t stats;
thread_pool_get_stats(server->thread_pool, &stats);
printf("线程池完成任务: %lld\n", stats.tasks_completed);
}
int main() {
printf("高性能Reactor模式网络服务器\n");
reactor_server_t *server = server_create(8080, 8); // 8个工作线程
if (!server) {
printf("服务器创建失败\n");
return 1;
}
// 启动服务器
server_run(server);
// 注意:server_run是阻塞的,正常情况下不会返回
// 在实际应用中,应该处理信号和优雅关闭
return 0;
}
由于篇幅限制,提供第九、十章的详细内容,涵盖了高级线程池实现、无锁编程和实际的高性能网络服务器案例。这些内容展示了如何将pthread.h的各种特性应用于实际的高性能系统中。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------更新于2025.11.9
9305

被折叠的 条评论
为什么被折叠?



