目录
1.线程概念
1.1 线程的核心特点
1.2线程的工作模型
1.3线程的潜在问题
1.4 进程和线程区别
1.4.1执行与调度
1.4.2进程和线程区别对比表
1.4.3应用场景
1.4.4总结
2.线程的创建
2.1验证进程结束后,进程中所有的线程都会强制退出
2.2线程函数正常执行
3.线程调度机制
3.1调度策略与优先级
3.2不同调度策略的对比
3.3 调度触发机制
3.4 线程默认调度机制验证
4.线程函数传参
1.线程概念

1.1 线程的核心特点
- 内存空间(堆、全局变量)
- 打开的文件、网络连接等
- 代码段(程序指令)
- 环境变量
线程间通信可直接通过共享内存,无需复杂的进程间通信(IPC)。
- 线程ID(TID)
- 程序计数器(PC)
- 寄存器集合
- 栈空间(用于保存局部变量、函数调用链)
1.2线程的工作模型
1.3线程的潜在问题
- 内存消耗增加(每个线程需独立栈空间)。
- CPU频繁切换线程,降低效率。
1.4 进程和线程区别
1.4.1执行与调度
(1)进程: 操作系统以进程为单位分配CPU时间片,进程是资源分配的基本单位。
多进程程序可以充分利用多核CPU(并行执行)。
(2)线程: 线程是CPU调度的基本单位,同一进程的线程共享进程的时间片。
多线程程序在单核CPU上通过时间片切换实现“并发”,在多核CPU上可实现并行。
1.4.2进程和线程区别对比表
特性 | 进程 | 线程 |
---|---|---|
资源独立性 | 独立内存和资源 | 共享进程内存和资源 |
创建/切换开销 | 高 | 低 |
通信成本 | 高(需IPC) | 低(直接共享内存) |
容错性 | 高(崩溃不影响其他进程) | 低(线程崩溃可能影响整个进程) |
适用场景 | 隔离性要求高、任务独立 | 高并发、数据共享需求高 |
1.4.3应用场景
(1)适合多进程的场景:
需要高隔离性(如浏览器、虚拟机)。
任务间无紧密协作,且需避免单点故障。
(2)适合多线程的场景:
需要高效共享数据(如Web服务器处理并发请求)。
计算密集型任务拆分到多核并行处理(如科学计算)。
1.4.4总结
2.线程的创建
函数原型:
#include <pthread.h>int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);功能:
创建一个线程。参数:
thread:线程标识符地址。
attr:线程属性结构体地址(默认 NULL)。
start_routine:线程函数的入口地址。
arg:传给线程函数的参数。返回值:
成功:返回 0
失败:返回错误码(如 EAGAIN 表示资源不足,EINVAL 表示属性无效)
2.1验证进程结束后,进程中所有的线程都会强制退出
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>//由于线程库原本不是系统本身的,所以在链接时需要手动链接库文件 gcc *.c -lpthreadvoid *thread_fun(void *arg)
{printf("子线程正在运行\n");
}int main(int argc, char const *argv[])
{printf("主控线程正在执行\n");pthread_t thread;//通过pthread_create函数创建子线程if(pthread_create(&thread, NULL, thread_fun, NULL) != 0){perror("fail to pthread_create");//创建失败exit(1);//退出}//由于进程结束后,进程中所有的线程都会强制退出,所以现阶段不要让进程退出// while(1);return 0;
}
运行结果:编译时加-lpthread, gcc 01_pthread.c -lpthread
程序运行时,main函数执行完直接退出,线程也会退出,执行线程的函数未执行。
2.2线程函数正常执行
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>//由于线程库原本不是系统本身的,所以在链接时需要手动链接库文件 gcc *.c -lpthreadvoid *thread_fun(void *arg)
{printf("子线程正在运行\n");
}int main(int argc, char const *argv[])
{printf("主控线程正在执行\n");pthread_t thread;//通过pthread_create函数创建子线程if(pthread_create(&thread, NULL, thread_fun, NULL) != 0){perror("fail to pthread_create");//创建失败exit(1);//退出}//sleep(1); // 使用sleep() 也能保证线程函数执行。//由于进程结束后,进程中所有的线程都会强制退出,所以现阶段不要让进程退出while(1);return 0;
}

3.线程调度机制
3.1调度策略与优先级
(1)普通线程调度
默认策略:采用 完全公平调度器(CFS),基于时间片轮转和进程的 nice 值分配 CPU 时间。
调度目标:保证所有线程公平使用 CPU,运行时间与 nice 值成反比(nice 值范围:-20~19,默认 0)。
(2)实时线程调度
策略类型:
SCHED_FIFO:先进先出,高优先级线程独占 CPU 直至主动释放或阻塞。
SCHED_RR:时间片轮转,高优先级线程运行固定时间片(默认 100ms)后被抢占。
优先级范围:实时线程优先级为 1~99(1最低,99最高),始终优先于普通线程。
(3)优先级管理 实时线程优先级通过 sched_setscheduler 设置,普通线程优先级通过 nice 调整。 调度器优先执行高优先级线程队列的头部线程,同优先级按策略(FIFO/RR)排序。
3.2不同调度策略的对比
调度策略 | 调度机制 | 是否依赖时间片 | 上下文切换触发条件 |
---|---|---|---|
CFS(普通线程) | 基于虚拟时间公平分配 CPU | 否 | vruntime 差距过大、高优先级线程就绪 |
SCHED_RR | 固定时间片轮转 | 是(如 100ms) | 时间片耗尽、更高优先级线程就绪 |
SCHED_FIFO | 先进先出,无时间片限制 | 否 | 线程主动让出或更高优先级线程抢占 |
SCHED_DEADLINE | 优先执行截止时间(Deadline)最近的线程 | 否 | Deadline 到期或更高优先级线程就绪 |
3.3 调度触发机制
(1)调度时机
主动触发:系统调用返回、线程阻塞/唤醒、线程退出。
被动触发:时钟中断(检查时间片耗尽)、高优先级线程就绪。
抢占规则:高优先级线程可抢占低优先级线程,实时线程可抢占普通线程。
(2)时间片分配
实时线程时间片固定(如 RR 策略的 100ms),普通线程时间片由 CFS 动态计算(基于 nice 值和系统负载)。
3.4 线程默认调度机制验证
程序:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>//一个进程中的多个线程执行顺序是不确定的,没有先后顺序可言
//多线程执行时跟进程一样,是来回切换运行的,跟进程的调度机制一样void *pthread_fun1(void *arg)
{printf("子线程1开头 正在运行\n");sleep(1);printf("子线程1结尾 正在运行\n");
}void *pthread_fun2(void *arg)
{printf("子线程2开头 正在运行\n");sleep(1);printf("子线程2结尾 正在运行\n");
}void *pthread_fun3(void *arg)
{printf("子线程3开头 正在运行\n");sleep(1);printf("子线程3结尾 正在运行\n");
}int main(int argc, char const *argv[])
{pthread_t thread1, thread2, thread3;if(pthread_create(&thread1, NULL, pthread_fun1, NULL) != 0){perror("fail to pthread_create thread1");}if(pthread_create(&thread2, NULL, pthread_fun2, NULL) != 0){perror("fail to pthread_create thread2");}if(pthread_create(&thread3, NULL, pthread_fun3, NULL) != 0){perror("fail to pthread_create thread3");}while(1);return 0;
}
运行结果:
一个进程中的多个线程执行顺序是不确定的,多线程执行时跟进程一样,是来回切换运行的,跟进程的调度机制一样。
4.线程函数传参
程序:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>int num = 100;//全局变量,线程共享内存//线程处理函数可以认为就是一个普通的全局函数,只不过与普通函数最大的区别
//在于,线程处理函数是并行执行,来回交替执行,但是普通函数一定是按照顺序一个一个执行
void *pthread_fun1(void *arg)
{printf("子线程1:num = %d\n", num);num++;//修改全局变量,其他线程获取到的是修改后的值int n = *(int *)arg;// arg强转为 int *printf("main函数局部变量a修改前,在子线程1为: %d\n", n);*(int *)arg = 111;//修改局部变量 a ,其他线程获取到的是修改后的值n = *(int *)arg;printf("main函数局部变量a修改后,在子线程1为: %d\n", n);
}void *pthread_fun2(void *arg)
{sleep(1);//保证 pthread_fun1 先执行完printf("子线程2:num = %d\n", num);int n = *(int *)arg;printf("main函数局部变量a,在子线程2为: %d\n", n);
}int main(int argc, char const *argv[])
{pthread_t thread1, thread2;int a = 666;if(pthread_create(&thread1, NULL, pthread_fun1, (void *)&a) != 0){perror("fail to pthread_create");}if(pthread_create(&thread2, NULL, pthread_fun2, (void *)&a) != 0){perror("fail to pthread_create");}while(1);return 0;
}
运行结果:全局变量、局部变量在线程1修改后,执行线程2获取到的变量为修改后变量。