个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创Linux系统基础-多线程超详细讲解(1)
收录于专栏[Linux学习]
本专栏旨在分享学习Linux的一点学习笔记,欢迎大家在评论区交流讨论💌
目录
1. 线程的概念
2. 线程的优缺点
线程的优点 :
线程的缺点 :
3. 线程用途
4. Linux进程VS线程
进程和线程区分
进程和线程关系图解
5. 线程异常
1. 线程的概念
1. 在一个程序里面的一个执行路线就叫做线程 (thread). 更准确的定义是 : 线程是 "一个进程内部的控制序列"
2. 一切进程至少都有一个执行线程
3, 线程在进程内部运行, 本质是在进程地址空间内运行
4. 透过进程虚拟空间, 可以看到进程的大部分资源, 将进程资源合理分配给每个执行流, 就形成了线程执行流
总结 :
进程 = 内核数据结构 + 进程代码和数据 进程承担分配系统资源的基本实体!
线程 : 在进程内部运行, 是CPU调度的基本单位
2. 线程的优缺点
线程的存在带来了一个问题 : 已经有多进程和进程池了, 为什么还需要多线程呢?
这就不得不谈一下线程的优缺点了:
线程的优点 :
1. 创建一个新线程的代价要比创建一个新进程小的多!
2. 相比于进程之间的切换相比, 线程之间的切换需要操作系统的工作要少很多
线程通常共享同一进程的内存空间,因此当线程切换时,许多数据和代码仍然在缓存中。这种共享提高了缓存的命中率,减少了从主内存读取数据的需要。
进程切换通常涉及更改整个进程的地址空间。当一个进程切换到另一个进程时,原有的缓存数据往往会被新的进程的缓存替换,这导致了缓存失效(cache misses)。这意味着需要更多的时间去重新加载所需的数据。
3. 线程占用的资源要比进程少很多
4. 能充分利用多处理器的可并行数量
5. 在等待慢速I/O操作结束的同时, 程序可执行其他的计算任务
6. 计算密集型应用, 为了能在多处理器系统上运行, 将计算分解到多个线程中实现
7. I/O密集型应用, 为了能提高性能, 将I/O操作重叠, 线程可以同时等待不同的I/O操作
线程的缺点 :
1. 性能损失
一个很少被外部事件阻塞的计算密集型线程往往无法于同它线程共享一个处理器, 如果计算密集型线程的数量比可用的处理器多, 那么可能会有比较大的性能损失, 这里的性能损失是额外的同步和调度开销, 而可用资源不变
2. 健壮性降低
编写多线程需要更全面更深入的考虑, 在一个多线程程序里, 因时间分配上的细微偏差或者因共享了不该共享的变量而造成了不良影响的可能性是很大的, 换句话说, 线程之间是缺乏保护的
3. 缺乏访问控制
进程是访问控制的基本粒度, 在一个线程中调用某些OS函数会对整个进程造成影响.
4. 编程难度提高
编写与调试一个多线程程序比单线程程序困难的多
3. 线程用途
并发执行:
线程允许程序在同一进程中同时执行多个任务,提高程序的并发性和响应速度。例如,用户界面线程可以与后台处理线程并行工作,保持应用程序的响应性。
资源共享:
线程在同一进程中共享内存和资源,这使得数据共享更加高效。线程之间的通信和数据传递相比进程间通信(IPC)更简单,减少了数据复制和上下文切换的开销。
提高性能:
在多核处理器上,多个线程可以并行执行,从而充分利用多核的计算能力,提高应用程序的性能。例如,图像处理、数据分析等任务可以通过多线程加速处理。
异步操作:
线程可以用于实现异步操作,使得程序在等待某些耗时操作(如I/O操作、网络请求)时不会阻塞主执行流。例如,网络下载可以在一个线程中进行,主线程仍然可以处理用户输入。
后台处理:
线程适合执行需要长时间处理的任务,而不影响主程序的性能。例如,定期执行的任务(如日志记录、数据备份)可以在后台线程中运行。
简化设计:
在某些应用中,使用线程可以使程序设计更为简单清晰。比如,使用线程池可以管理多个任务并减少资源的管理复杂性。
游戏和图形处理:
在游戏开发中,多个线程可用于处理物理运算、图形渲染和AI计算,使游戏更加流畅和高效。
服务器应用:
在服务器应用中,线程可以用于处理多个并发请求,例如Web服务器通常会为每个请求创建一个线程,以提高处理能力和响应速度。
4. Linux进程VS线程
进程和线程区分
进程是资源分配的基本单位
线程是调度的基本单位
线程共享进程数据, 但也拥有自己的一部分数据:
线程ID
一组寄存器
栈
error
信号屏蔽字
调度优先级
进程的多个线程共享同一地址空间, 因此Text Segment, Data Segment都是共享的, 如果定义一个函数, 在各个线程中都可以调用, 如果定义一个全局变量在各个线程总都可以访问, 除此之外, 各线程还共享以下进程资源和环境:
1. 文件描述符表
2. 每种信号的处理方式
3. 当前工作目录
4. 用户id和组id
进程和线程关系图解
进程和线程关系如下图所示:
5. 线程异常
单个线程如果出现除零, 野指针问题导致线程崩溃, 进程也会随着崩溃
线程是进程的执行分支, 线程出现异常, 就类似进程出异常, 进而触发信号机制, 终止进程, 进程终止, 该进程内的所有线程也就随之退出
代码示例:
#include <iostream>
#include <unistd.h>
#include <ctime>int gval = 100;void *threadStart(void *args)
{while(true){sleep(1);int x = rand() % 5;std::cout << "new thread running..." << "pid: " << getpid() << ", gval: " << gval << ", &gal: " << &gval << std::endl;if(x == 0){int *p = nullptr;*p = 100;//野指针}}
} int main()
{srand(time(nullptr));pthread_t tid1;pthread_create(&tid1, nullptr, threadStart, (void *)"thread-new");pthread_t tid2;pthread_create(&tid2, nullptr, threadStart, (void *)"thread-new");pthread_t tid3;pthread_create(&tid3, nullptr, threadStart, (void *)"thread-new");pthread_t tid4;pthread_create(&tid4, nullptr, threadStart, (void *)"thread-new");//主线程while(true){std::cout << "main thread running..." << ", pid: " << getpid() << ", gval: " << gval << ", &gval: " << &gval << std::endl;gval++;sleep(1);}
}