Linux 多线程编程实例

在操作系统领域,多线程编程是提升程序性能和响应能力的重要手段,Linux 作为开源操作系统的代表,提供了强大的多线程支持,主要通过 POSIX 线程(Pthreads)库实现,本文将通过一个具体的实例,详细介绍 Linux 多线程编程的核心概念、实现方法及注意事项,帮助读者理解多线程编程的实践技巧。
多线程编程基础
多线程是指在一个进程中创建多个执行线程,每个线程拥有独立的执行栈,但共享进程的地址空间、文件描述符等资源,与多进程相比,多线程的创建和切换开销更小,适合处理需要频繁交互或共享数据的任务,在 Linux 中,Pthreads 库提供了丰富的 API 来管理线程的生命周期,包括线程创建、同步、通信等操作。
使用 Pthreads 编程时,需要包含 <pthread.h> 头文件,并在编译时链接 -pthread 选项,编译命令为 gcc -o program program.c -pthread,Pthreads 的核心数据结构是 pthread_t,用于标识线程,而线程的入口点则通过函数指针指定。
多线程实例:并行计算数组
为了演示多线程编程的实际应用,我们以并行计算数组元素的和为例,假设有一个包含 100 万个整数的数组,我们将其分为 4 个部分,由 4 个线程分别计算各部分的和,最后由主线程汇总结果。
线程参数与数据结构
在多线程编程中,线程间需要共享数据,为了避免数据竞争,通常通过结构体传递参数,定义如下结构体存储线程计算所需的数组、起始索引、结束索引及结果:

typedef struct {
int *array; // 待计算的数组
int start; // 起始索引
int end; // 结束索引
long long sum; // 计算结果
} ThreadData;
线程函数实现
每个线程的入口点函数需要接收一个 void* 类型的参数,并在内部转换为 ThreadData 结构体,线程函数遍历指定范围的数组元素,累加求和:
void *calculate_sum(void *arg) {
ThreadData *data = (ThreadData *)arg;
data->sum = 0;
for (int i = data->start; i < data->end; i++) {
data->sum += data->array[i];
}
pthread_exit(NULL);
}
主线程创建与同步
主线程负责初始化数组、创建子线程并等待其完成,使用 pthread_create 创建线程,pthread_join 等待线程结束并获取结果:
#define THREAD_COUNT 4
#define ARRAY_SIZE 1000000
int main() {
int array[ARRAY_SIZE];
pthread_t threads[THREAD_COUNT];
ThreadData thread_data[THREAD_COUNT];
long long total_sum = 0;
// 初始化数组(示例:填充随机数)
for (int i = 0; i < ARRAY_SIZE; i++) {
array[i] = rand() % 100;
}
// 分配任务给各线程
int chunk_size = ARRAY_SIZE / THREAD_COUNT;
for (int i = 0; i < THREAD_COUNT; i++) {
thread_data[i].array = array;
thread_data[i].start = i * chunk_size;
thread_data[i].end = (i == THREAD_COUNT - 1) ? ARRAY_SIZE : (i + 1) * chunk_size;
pthread_create(&threads[i], NULL, calculate_sum, &thread_data[i]);
}
// 等待线程结束并汇总结果
for (int i = 0; i < THREAD_COUNT; i++) {
pthread_join(threads[i], NULL);
total_sum += thread_data[i].sum;
}
printf("Total sum: %lld\n", total_sum);
return 0;
}
线程同步与互斥锁
在上述实例中,各线程仅读取数组且无共享写入,因此无需同步,但在实际应用中,多个线程同时修改共享数据时,会导致数据不一致,此时需要使用互斥锁(Mutex)保护临界区。
修改线程函数使其将部分和写入全局变量,并通过互斥锁保护该变量:
#include <pthread.h>
long long global_sum = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *calculate_sum(void *arg) {
ThreadData *data = (ThreadData *)arg;
long long local_sum = 0;
for (int i = data->start; i < data->end; i++) {
local_sum += data->array[i];
}
// 加锁保护全局变量
pthread_mutex_lock(&mutex);
global_sum += local_sum;
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
线程池优化
频繁创建和销毁线程会带来性能开销,在实际应用中,可以采用线程池(Thread Pool)技术,预先创建一组线程并复用它们,线程池的核心思想是:主线程将任务放入任务队列,工作线程从队列中获取任务并执行。

以下是线程池的简化实现步骤:
- 初始化任务队列(如链表或环形缓冲区)。
- 创建固定数量的工作线程,每个线程循环从队列中获取任务并执行。
- 主线程提交任务到队列,无需关心线程的创建与销毁。
线程池特别适合处理大量短小任务,如 Web 服务器、并行计算等场景。
多线程编程注意事项
- 避免数据竞争:对共享数据的访问必须通过互斥锁、信号量等同步机制保护。
- 防止死锁:确保锁的获取顺序一致,避免线程因互相等待而阻塞。
- 资源释放:线程退出时确保释放动态分配的内存、关闭文件描述符等资源。
- 可移植性:Pthreads 是 POSIX 标准,但在 Windows 等平台需使用不同的 API(如
CreateThread)。
通过并行计算数组实例,我们展示了 Linux 多线程编程的基本流程,包括线程创建、数据共享、同步机制等,多线程编程能够充分利用多核 CPU 的计算能力,但需要仔细处理线程间的交互问题,在实际开发中,合理使用线程池、互斥锁等工具,可以显著提升程序的并发性能和稳定性,掌握多线程编程技巧,对于开发高性能 Linux 应用具有重要意义。



















