一、线程基础概念
1.1 什么是线程?
在Linux系统中,线程是轻量级的进程,它们属于某个进程,共享进程的资源,但拥有独立的执行流。
核心特征:
进程是系统中最小的资源分配单位
线程是系统中最小的执行单位
进程中,线程与线程是平级关系
进程中默认有一个主线程(main函数所在线程)
1.2 线程与进程的核心区别
特性 | 进程 | 线程 |
|---|---|---|
资源共享 | 资源独立,不共享 | 共享进程资源(全局变量、堆、文件描述符等) |
栈空间 | 独立地址空间 | 每个线程有独立栈区(默认8MB),但共享堆和全局区 |
稳定性 | 相对稳定,一个进程崩溃不影响其他进程 | 不稳定,一个线程崩溃会导致整个进程崩溃 |
创建开销 | 大(需创建3GB虚拟地址空间) | 小(只需在进程空间中分配新的栈区) |
并发度 | 较低,上下文切换开销大 | 较高,上下文切换开销小 |
通信方式 | 复杂(管道、消息队列、共享内存等) | 简单(直接读写共享变量) |
1.3 线程的主要作用
并发执行:充分利用多核CPU,提高程序性能
处理耗时任务:将耗时操作放到后台线程,保持界面响应
异步处理:处理I/O密集型任务,避免阻塞主线程
二、线程编程步骤(POSIX标准)
线程编程通常遵循以下步骤:
1. 创建线程 (pthread_create) 2. 线程执行任务 (线程函数) 3. 线程退出 (pthread_exit/return) 4. 线程资源回收 (pthread_join/pthread_detach)三、线程相关函数详解
3.1 线程创建:pthread_create
#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);参数解析:
参数 | 说明 | 示例 |
|---|---|---|
thread | 线程ID指针,函数返回创建的线程ID |
|
attr | 线程属性,NULL表示默认属性 |
|
start_routine | 线程函数指针,线程执行的入口 |
|
arg | 传递给线程函数的参数 | 任意类型指针 |
返回值:
成功:返回0
失败:返回错误码(非0值)
完整示例:
#include <stdio.h> #include <pthread.h> #include <unistd.h> // 线程函数 void* thread_func(void* arg) { int thread_num = *(int*)arg; printf("线程%d启动,线程ID: %lu\n", thread_num, pthread_self()); sleep(2); printf("线程%d结束\n", thread_num); return NULL; } int main() { pthread_t tid1, tid2; int arg1 = 1, arg2 = 2; // 创建线程1 if (pthread_create(&tid1, NULL, thread_func, &arg1) != 0) { perror("线程1创建失败"); return 1; } // 创建线程2 if (pthread_create(&tid2, NULL, thread_func, &arg2) != 0) { perror("线程2创建失败"); return 1; } // 等待线程结束 pthread_join(tid1, NULL); pthread_join(tid2, NULL); printf("主线程结束\n"); return 0; }3.2 获取线程ID:pthread_self
pthread_t pthread_self(void);功能:获取当前线程的线程ID
参数:无
返回值:当前线程的ID
示例:
printf("当前线程ID: %lu\n", pthread_self());线程ID格式化:
线程ID类型为
pthread_t,通常是无符号长整型打印时使用格式:
%lu(unsigned long int)
3.3 线程退出:pthread_exit
void pthread_exit(void *retval);功能:线程自行退出,不返回调用者
参数:
retval:线程退出时的返回值("临死遗言")
与exit()的区别:
pthread_exit()只退出当前线程exit()退出整个进程
示例:
void* thread_func(void* arg) { int* result = malloc(sizeof(int)); *result = 100; // 方式1:使用pthread_exit退出 pthread_exit(result); // 方式2:使用return退出 // return result; }3.4 线程取消:pthread_cancel
int pthread_cancel(pthread_t thread);功能:请求结束指定的线程
参数:
thread:要取消的线程ID
返回值:
成功:返回0
失败:返回非0错误码
注意事项:
被取消的线程需要有取消点(如sleep、read、write等系统调用)
线程可以设置取消状态,决定是否响应取消请求
线程被取消后,其资源需要被回收
示例:
#include <stdio.h> #include <pthread.h> #include <unistd.h> void* thread_func(void* arg) { printf("线程开始执行,5秒后结束\n"); // 设置线程可被取消 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); for (int i = 1; i <= 5; i++) { printf("线程运行中...%d秒\n", i); sleep(1); // 取消点 } printf("线程正常结束\n"); return NULL; } int main() { pthread_t tid; pthread_create(&tid, NULL, thread_func, NULL); sleep(3); // 主线程等待3秒 // 取消子线程 printf("主线程请求取消子线程\n"); pthread_cancel(tid); // 等待线程结束 pthread_join(tid, NULL); printf("子线程已被取消\n"); return 0; }3.5 线程回收(阻塞方式):pthread_join
int pthread_join(pthread_t thread, void **retval);功能:阻塞等待指定线程结束,并回收其资源
参数:
thread:要回收的线程IDretval:接收线程返回值的指针
返回值:
成功:返回0
失败:返回非0错误码
示例:
#include <stdio.h> #include <pthread.h> #include <stdlib.h> void* thread_func(void* arg) { int* result = malloc(sizeof(int)); *result = 42; // 计算结果 printf("子线程计算结果: %d\n", *result); pthread_exit(result); // 退出并返回结果 } int main() { pthread_t tid; int* thread_result; pthread_create(&tid, NULL, thread_func, NULL); // 阻塞等待线程结束,并获取返回值 if (pthread_join(tid, (void**)&thread_result) == 0) { printf("主线程收到子线程返回值: %d\n", *thread_result); free(thread_result); // 记得释放内存 } return 0; }3.6 线程分离:pthread_detach
int pthread_detach(pthread_t thread);功能:设置线程为分离状态,线程退出后系统自动回收资源
参数:
thread:要设置的线程ID(通常是自己的ID)
返回值:
成功:返回0
失败:返回非0错误码
关键特性:
分离后的线程不能被pthread_join回收
线程退出后,系统自动回收栈空间
主线程无需关心分离线程的回收问题
示例:
#include <stdio.h> #include <pthread.h> #include <unistd.h> void* thread_func(void* arg) { // 设置自己为分离状态 pthread_detach(pthread_self()); printf("分离线程开始执行\n"); sleep(2); printf("分离线程结束,资源将被系统自动回收\n"); return NULL; } int main() { pthread_t tid; pthread_create(&tid, NULL, thread_func, NULL); // 分离线程后,主线程不需要调用pthread_join sleep(1); printf("主线程继续执行其他任务\n"); sleep(3); // 等待分离线程结束 printf("主线程结束\n"); return 0; }四、线程编程综合示例
4.1 多线程计算示例
#include <stdio.h> #include <pthread.h> #include <stdlib.h> #define THREAD_COUNT 4 #define ARRAY_SIZE 1000000 int array[ARRAY_SIZE]; long long partial_sum[THREAD_COUNT] = {0}; // 线程函数:计算部分和 void* calculate_partial_sum(void* arg) { int thread_id = *(int*)arg; int start = thread_id * (ARRAY_SIZE / THREAD_COUNT); int end = (thread_id + 1) * (ARRAY_SIZE / THREAD_COUNT); printf("线程%d计算范围: %d ~ %d\n", thread_id, start, end - 1); for (int i = start; i < end; i++) { partial_sum[thread_id] += array[i]; } printf("线程%d部分和: %lld\n", thread_id, partial_sum[thread_id]); return NULL; } int main() { pthread_t threads[THREAD_COUNT]; int thread_ids[THREAD_COUNT]; // 初始化数组 for (int i = 0; i < ARRAY_SIZE; i++) { array[i] = i + 1; } // 创建多个线程 for (int i = 0; i < THREAD_COUNT; i++) { thread_ids[i] = i; if (pthread_create(&threads[i], NULL, calculate_partial_sum, &thread_ids[i]) != 0) { perror("线程创建失败"); return 1; } } // 等待所有线程结束 for (int i = 0; i < THREAD_COUNT; i++) { pthread_join(threads[i], NULL); } // 合并结果 long long total_sum = 0; for (int i = 0; i < THREAD_COUNT; i++) { total_sum += partial_sum[i]; } printf("数组总和: %lld\n", total_sum); printf("预期总和: %lld\n", (long long)ARRAY_SIZE * (ARRAY_SIZE + 1) / 2); return 0; }4.2 线程安全退出模式
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> // 全局标志,用于通知线程退出 volatile int exit_flag = 0; void* worker_thread(void* arg) { printf("工作线程启动\n"); while (!exit_flag) { printf("工作线程执行任务...\n"); sleep(1); } printf("工作线程收到退出信号,准备退出\n"); return NULL; } void signal_handler(int sig) { if (sig == SIGINT) { printf("\n收到Ctrl+C信号,通知线程退出\n"); exit_flag = 1; } } int main() { pthread_t tid; // 设置信号处理 signal(SIGINT, signal_handler); // 创建工作线程 if (pthread_create(&tid, NULL, worker_thread, NULL) != 0) { perror("线程创建失败"); return 1; } printf("主线程运行中,按Ctrl+C退出程序\n"); // 等待工作线程退出 pthread_join(tid, NULL); printf("程序正常退出\n"); return 0; }六、编译与运行
编译时需要链接pthread库:
# 编译命令 gcc -o thread_demo thread_demo.c -pthread # 运行程序 ./thread_demo总结
本文全面介绍了Linux线程编程的核心概念和关键技术:
主题 | 核心内容 | 关键函数 |
|---|---|---|
线程概念 | 轻量级进程,共享资源,独立执行 | - |
线程创建 | 创建新线程执行指定函数 |
|
线程标识 | 获取当前线程ID |
|
线程退出 | 线程主动退出并返回值 |
|
线程取消 | 请求终止其他线程 |
|
线程回收 | 阻塞等待线程结束并回收资源 |
|
线程分离 | 设置线程自动回收 |
|