尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

学习笔记 | Linux多线程基础:从线程创建到资源回收

学习笔记 | Linux多线程基础:从线程创建到资源回收 一为什么需要多线程1.1 什么是线程进程是资源分配的最小单位线程是CPU调度的最小单位。一个进程内部可以创建多个线程所有线程共享该进程的地址空间全局变量文件描述符每个线程都由自己独立栈寄存器。1.2 需要多线程的原因①可以充分利用多核的CPU算力多个线程分配到不同的CPU核并行执行提升整体的运算吞吐量。单核CPU下多线程是并发不是并行靠时间片轮转切换。②避免程序阻塞提升响应能力例如网络服务器中一个线程等待客户端的数据其他线程继续处理其他连接。③线程切换开销远小于进程线程之间的切换只需要切换寄存器栈切换成本低。④方便共享数据线程可以直接读取全局变量。场景类型特点多线程作用典型例子CPU密集型程序主要消耗CPU计算资源将计算任务分解到多个CPU核心并行执行缩短总耗时视频编码科学计算图像渲染IO密集型程序主要等待输入和输出操作一个线程等待IO时其他线程继续工作避免CPU空闲Web服务器数据库下载工具二线程和进程的关系及区别2.1 二者的区别对比项进程线程基本空间资源分配的基本单位CPU调度的基本单位地址空间独立拥有共享进程的地址空间创建开销大小切换开销大小隔离性强弱2.2 线程独有的资源私有线程ID一组寄存器用于上下文切换栈存放局部变量函数调用error错误码信号屏蔽字调度优先级2.3线程共享的资源共有内存资源和系统资源。三线程控制3.1 POSIX线程库需要引入头文件pthread.h3.2 函数pthread_create创建线程的入口函数所有多线程程序都是从这里开始。返回的是pthread_t类型的线程IDpthread_join / pthread_detach资源回收的两种方式join是手动回收detach是自动回收。pthread_exit / pthread_cancel线程结束的两种方式exit是终止自己cancel是终止同一进程中的其他线程。3.3 线程等待为什么需要线程等待①已经退出的线程其空间没有被释放仍然在进程的空间地址内。②创建新的线程不会复用刚才退出线程的地址空间。pthread_join函数作用等待子进程结束并回收它的资源。3.4 分离线程3.4.1 为什么需要分离线程默认形况下新创建的线程是 joinable 的线程退出后必须用pthread_join回收资源否则会造成资源浪费如果不关心线程返回值每次都要join是一种负担。3.4.2 分离线程的作用告诉系统线程退出时自动释放资源无需再等待pthread_join。四共享资源和竞态条件4.1 多个线程修改同一个变量会发生什么多个线程同时修改同一个全局变量没有任何保护会产生竞态条件。这个时候就可以通过添加锁来保证同一时刻只有一个线程进入临界区操作资源。竞态条件程序的最终结果依赖于多个线程的CPU调度执行时序。示例多个线程同时计数累加实际运行结果小于预期值因为一个线程读取变量之后还没写回就被内核切走另一个线程修改了同一个变量数据被覆盖丢失。五常见问题汇总1.并发和并行有什么区别并发强调多个任务在一段时间内交替进行不一定是同时进行并行强调的是多个任务在同一时刻同时执行通常需要多个CPU核心。2.创建线程之后线程的执行顺序是固定的吗不是固定的线程创建成功之后执行的顺序通常由操作系统调度器决定顺序。3.为什么不能用sleep代替pthread_joinsleep只能让当前线程暂停一段时间不能保证目标线程已经执行完成。例如线程任务可能因为系统负载CPU调度或任务复杂度不同执行时间超过预期的睡眠时间这样的情况下sleep睡眠时间一过主线程继续向下执行了就不会等待指定线程执行完成只有pthread_join是真正的等待指定线程结束的操作。4.pthread_join 和 pthread_detach 有什么区别对比项pthread_joinpthread_detach是否等待线程结束是调用后线程阻塞等待目标线程退出否立即返回不阻塞是否能获取返回值可以不可以线程退出后直接丢弃资源释放时机调用之后才回收线程资源如果不join 线程结束后资源不会释放变成僵尸进程线程一旦执行结束系统自动回收线程资源无须外部调用回收函数适用场景需要拿到子线程执行结果主线程要等待子线程做完任务往下执行不关心线程返回结果不需要等待线程结束做完任务线程自动销毁5.为什么需要pthread_join呢没有调用这个函数的话如果主线程直接返回或者进程中任意一个线程调用exit整个进程都会结束进程中的其他线程也会被终止因此调用 pthread_join 后主线程会等待子线程完成之后才会继续执行。6.循环创建线程时为什么不能直接传递i如果传 i当线程真正开始运行时i 的值可能已经被修改导致多个线程读取到相同的或者错误的值。解决办法为每个线程准备独立的参数,可以增加一个数组如下int args[3]; for (int i 0; i 3; i) { args[i] i; pthread_create(threads[i], NULL, worker, args[i]); }
返回列表