Linux软件编程:进程与线程(线程)
一、线程的本质
1. 线程是操作系统调度的最小执行单元,共享进程的资源(内存、文件等),但拥有独立的栈空间(存储局部变量)、寄存器状态(程序计数器等)、线程ID和优先级
2.Linux线程实现原理:Linux通过轻量级进程(LWP)实现线程,关键系统调用
二、为什么需要多线程?
场景类型优势体现嵌入式案例响应优化分离阻塞操作串口通信+UI响应分离性能提升多核CPU并行计算图像处理流水线资源复用共享内存减少拷贝开销多传感器数据融合模块解耦功能隔离降低复杂度网络协议栈分层实现
三、多线程进阶:线程池的诞生
线程池核心原理:线程池就是提前创建好一堆线程,所有线程阻塞等待一个队列,当用户提交一个任务,就唤醒一个线程执行任务。往复循环。
四、线程管理机制
1.动态扩缩容:根据负载自动增减线程数
2.保活机制:空闲线程超时自动回收
3.异常处理:线程崩溃后自动重启
五、面试常见问题
1.进程 vs 线程的区别?
进程:资源分配的最小单位,有独立地址空间(代码、数据、堆栈),切换开销大。
线程:CPU调度的最小单位,共享进程资源(内存、文件描述符),切换开销小,通信高效。
关键点:线程更轻量,适合嵌入式资源受限场景。
2.互斥锁(mutex)与信号量(semaphore)的区别?
特性互斥锁 (mutex)信号量 (semaphore)用途保护共享资源控制并发访问数量所有权锁的持有者必须释放任意线程可释放初始值1(锁定/未锁定)可设为N(资源数量)嵌入式注意需避免优先级反转适合生产者-消费者模型
3.什么是优先级反转?如何解决?
优先级继承(Linux默认):持有锁的线程临时继承等待线程的最高优先级。
优先级天花板:锁绑定一个优先级,持有锁的线程自动提升到该优先级。
现象:低优先级线程持有锁,中优先级线程抢占,高优先级线程因等待锁被阻塞。
4.如何避免死锁?
锁顺序:所有线程按固定顺序获取锁(如锁A→锁B)。
超时机制:pthread_mutex_timedlock() 避免无限等待。
死锁检测:工具如Valgrind的Helgrind插件。
5.自旋锁(spinlock) vs 互斥锁的适用场景?
自旋锁:忙等待,适用于临界区执行时间极短(如<2个时间片)且多核环境。
互斥锁:睡眠等待,适用于临界区较长或单核系统。
注意:嵌入式实时系统(RTOS)中慎用自旋锁,可能破坏实时性。
6.pthread_create() 失败的可能原因?
资源耗尽(线程数超过ulimit -u限制)
内存不足(无法分配线程栈,默认约8MB)
权限问题(嵌入式系统可能限制线程创建)
7.如何设置线程栈大小?
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024*128); // 设为128KB
pthread_create(&tid, &attr, thread_func, NULL);
8.如何设置线程优先级?
struct sched_param param;
param.sched_priority = 90; // 优先级值(1~99,越高越优先)
pthread_attr_setschedpolicy(&attr, SCHED_FIFO); // 实时调度策略
pthread_attr_setschedparam(&attr, ¶m);
注意:需要root权限或CAP_SYS_NICE能力。
9.如何定位多线程问题?
gdb:thread apply all bt 查看所有线程堆栈。
strace -f:跟踪线程系统调用。
Valgrind:检测内存竞争(--tool=helgrind)。
日志追踪:添加线程ID打印(pthread_self())。
10.共享内存访问的优化方法?
无锁编程:使用原子操作(atomic_inc())。
线程局部存储:__thread关键字避免竞争。
减少锁粒度:分段锁(如哈希桶锁)。