一、线程基础概念
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:要回收的线程ID -
retval:接收线程返回值的指针
返回值:
-
成功:返回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 |
|
|
线程退出 |
线程主动退出并返回值 |
|
|
线程取消 |
请求终止其他线程 |
|
|
线程回收 |
阻塞等待线程结束并回收资源 |
|
|
线程分离 |
设置线程自动回收 |
|
1463

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



