青海住房和城乡建设部网站,下沙做网站软件,备案 网站名称怎么写,兼职做网站赚钱吗文章目录一、线程基本概念1.1 进程地址空间与页表1.2 页表结构1.3 线程的理解1.3.1 如何描述线程1.4 再谈进程1.5 代码理解1.5.1 原生库提供线程pthread_create1.6 资源共享问题1.7 资源私有问题二、总结2.1 什么是线程2.2 并行与并发2.3 线程的优点2.4 线程的缺点2.5 线程异常…
文章目录一、线程基本概念1.1 进程地址空间与页表1.2 页表结构1.3 线程的理解1.3.1 如何描述线程1.4 再谈进程1.5 代码理解1.5.1 原生库提供线程pthread_create1.6 资源共享问题1.7 资源私有问题二、总结2.1 什么是线程2.2 并行与并发2.3 线程的优点2.4 线程的缺点2.5 线程异常2.6 进程与线程间的关系一、线程基本概念
1.1 进程地址空间与页表 注意这里的页表部分 在上一章【linux】进程信号——信号的保存和处理中我们讲了页表有用户级页表和内核级页表。如图其实页表还有其他很多属性。 举个例子当我们对常量区的数据进行修改时为什么会报错呢 OS会先通过页表找到物理地址然后查RWX权限发现只有R权限所以地址转换单元MMU会硬件报错转化成信号终止进程段错误。 而经过U/K权限的时候如果是U就直接访问是K就会去CPU查看当前的运行级别是内核级别才能访问带K的映射关系。
那么该如何看待进程地址空间和页表呢 1️⃣ 进程地址空间虚拟内存是进程能够看到的资源窗口。因为能看到的资源都是通过进程地址空间让我们看到的。 2️⃣ 页表是决定进程真正拥有资源的情况。 3️⃣ 合理的对进程地址空间页表进行资源划分就可以对进程的所有资源进行分类。 进程地址空间一共有2^32个地址。那么按道理页表也应该有2^32个条目我们就当一个条目大小为1byte也需要4GB的大小更何况每个条目还得存很多数据。所以页表不可能会这么使用。 那么真实的页表到底是什么样子呢
1.2 页表结构
首先说明几个点 1️⃣ 进程地址空间的一个地址我们称为虚拟地址有32个比特位。 2️⃣ 物理内存实际上也划分成了一个一个的数据页。OS为了管理每个数据页每个数据页都有一个描述的结构体非常小存储内存的属性。每个页框大小为4KB 3️⃣ 磁盘上的可执行程序在被编译的时候也被划分成一个一个的4KB大小的数据块我们把这种4KB的区域称为页帧。所以从磁盘加载到内存是以4KB为单位加载的。 虚拟地址的32个比特位并不是以一个整体转化的而是分成10、10、12三块二进制构成。 而页表也不止一张分为页目录、和页表。 先拿着虚拟地址的高十位去查页目录比如如果是0000000001就是第二个位置映射到指定的页表再通过中间10个比特位确定物理内存中页框的起始地址而一个页框的大小是4KB有2^12字节刚好对应虚拟地址的低12位比特位就可以作为页内偏移量找到对应的位置。 这样我们在使用的时候有可能只使用了几个页表那么其他的页表就不会加载到内存只有需要的时候才会创建。由此解决了内存不足的问题。
1.3 线程的理解
首先要知道线程是进程内的一个执行流。
我们知道创建一个进程就会连着创建PCB虚拟内存、页表。现在我们可以创建一个“进程”PCB直接指向虚拟内存就像下边的绿色的task_struct。 例如代码区有一大段代码我们现在就可以划分成几个小段代码分给每个“进程”。这样就实现了资源的分配。
我们可以通过虚拟地址空间和页表对进程进行资源划分而单个“进程”的执行力度一定要比之前一个进程要细。
1.3.1 如何描述线程
既然有多个线程那么OS就会采取先描述后组织的方式进行管理。那么怎么描述呢是创建一个新的结构体来描述吗 我们知道PCB是用来描述进程的那么描述线程的结构体我们叫做TCB线程控制块。 在windows中就是新创建了一个结构体来描述线程。 而单纯的从线程调度角度进程和线程有很多地方是重叠的。 所以在linux中没有创建针对线程的数据结构而是直接复用PCB用PCB来表示线程。 而CPU在进行调度的时候不关注到底是进程还是线程只看task_struct。 总结一下线程在进程内部进程的地址空间内执行拥有该进程的一部分资源。
1.4 再谈进程
什么叫做进程呢 我们把红色框框圈起来的整体叫做进程 PCB进程地址空间页表加载到物理内存的代码和数据。
从内核角度进程是承担分配系统资源的基本实体 在linux中线程是CPU调度的基本单位
而在之前的文章讲过的进程【linux】进程概念详述它讲的是只有一个PCB的进程只有一个执行流。 今天所讲述的是一个进程内有多个执行流的情况。
从CPU角度以前调度的就是一个进程今天就是调度进程中的一个分支。 所以现在CPU统一把task_struct看作成轻量级进程。
我们知道linux没有正真意义的线程这相比拥有真正线程的系统有什么优缺点呢 优点简单维护成本大大降低即可靠又高效。 缺点linux无法直接提供线程的基本调用接口只能提供创建轻量级进程的接口。 1.5 代码理解
1.5.1 原生库提供线程pthread_create
#include pthread.hint pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
Compile and link with -pthread.// 链接的时候必须加上-lpthreadRETURN VALUE
On success, pthread_create() returns 0;
on error, it returns an error number, and the contents of *thread are undefined.参数说明 thread线程id attr线程属性直接设为null start_routine函数指针 arg这个参数会传递进start_routine的void*参数中。
这里在链接的时候要注意link到系统给的原生线程库-lpthread。 说明一下这个原生线程库 因为用户只关注线程但是OS不提供线程的接口只提供创建轻量级进程的接口。所以在用户和OS之间加了一个用户级线程库。 向上提供各种线程接口向下把对线程的各种操作转化为对轻量级进程的各种操作。 这个库在任何linux操作系统都默认存在。
// Makefile
mythread:mythread.ccg -o $ $^ -lpthread -stdc11
.PHONY:clean
clean:rm -f mythread// mythread.cc
#include iostream
#include pthread.h
#include cassert
#include unistd.husing std::cout;
using std::endl;void* thread_stream(void *str)
{while(true){cout i am new thread endl;sleep(1);}
}int main()
{pthread_t tid;int n pthread_create(tid, nullptr, thread_stream, (void*)thread one);assert(n 0);(void)n;// 主线程while(true){cout i am main thread endl;sleep(1);}return 0;
}现象运行了两个执行流查看只有一个进程杀死进程两个执行流全部被杀死。 如果想看到这两个轻量级线程 使用指令ps -aL 可以看到两个PID一样说明属于同一个进程。而这里可以看到LWP不同这里的LWP就表示轻量级进程ID。 细节主线程的PID和LWP一样。
所以CPU在调度的时候用的就是LWP来作为标识符表示特定的执行流。 当只有一个单进程的时候PID和LWP是等价的。
那么这个tid到底是什么呢 我们可以修改一下代码进行验证
int main()
{pthread_t tid;int n pthread_create(tid, nullptr, thread_stream, (void*)thread one );assert(n 0);(void)n;// 主线程while(true){char buf[64];snprintf(buf, sizeof(buf), 0x%x, tid);cout i am main thread tid: buf endl;sleep(1);}return 0;
}这里只需要知道tid就是一个地址后面会详细介绍。
1.6 资源共享问题
线程一旦被创建几乎所有的资源都是被所有线程共享的。 比如 文件描述符表 每种信号处理方式SIG,IGN,SIG_DFL或者自定义信号处理函数 当前工作目录 用户id和组id #include iostream
#include pthread.h
#include cassert
#include unistd.h
#include cstdiousing std::cout;
using std::endl;void fun()
{cout 这是一个独立的方法 endl;
}void* thread_stream(void *str)
{while(true){cout i am new thread, name: (const char*)str;fun();sleep(1);}
}int main()
{pthread_t tid;int n pthread_create(tid, nullptr, thread_stream, (void*)thread one );assert(n 0);(void)n;// 主线程while(true){char buf[64];snprintf(buf, sizeof(buf), 0x%x, tid);cout i am main thread tid: buf;fun();sleep(1);}return 0;
}可以看到这个函数可以被多个线程同时访问。
那么全局变量呢
int cnt 0;void* thread_stream(void *str)
{while(true){cout i am new thread, name: (const char*)str cnt: cnt cnt: cnt endl;sleep(1);}
}int main()
{pthread_t tid;int n pthread_create(tid, nullptr, thread_stream, (void*)thread one );assert(n 0);(void)n;// 主线程while(true){char buf[64];snprintf(buf, sizeof(buf), 0x%x, tid);cout i am main thread tid: buf cnt: cnt cnt: cnt endl;sleep(1);}return 0;
}只要有一个线程中改变了也会影响另一个进程。 由此可见线程之间通信非常容易。
但是这样又会引发另一个问题。
1.7 资源私有问题
线程也要有自己的私有资源那么什么资源应该是线程所私有的呢 1️⃣ PCB的属性优先级上下文线程动态切换状态……。 2️⃣ 每一个线程都有自己独立的栈结构保存私有数据。 二、总结
2.1 什么是线程
笼统的讲线程是在进程内部运行的一个执行分支执行流属于进程的一部分粒度要比进程更加细致和轻量化。 在一个程序里的一个执行路线叫做线程更准确的定义是线程是”一个进程内部的控制序列“一切进程至少都有一个执行线程线程在进程内部运行本质是在进程地址空间内运行在Linux系统中在CPU眼里看到的PCB都要比传统的进程更加轻量化透过进程虚拟地址空间可以看到进程大部分资源将进程资源合理分配给每个执行流就形成了线程执行流。 2.2 并行与并发
并行多个执行流在同一刻拿着不同的CPU进行运算。 并发多个执行流在同一时刻只有一个执行流拥有CPU进行运算。
2.3 线程的优点
1️⃣ 创建线程的代价比创建进程小得多。因为不用创建地址空间、页表、加载代码数据只用创建一个PCB指向进程地址空间就够了。 2️⃣ 与进程之间的切换相比线程之间的切换需要操作系统做的工作要少很多。 进程要切换 页表、PCB、虚拟地址空间…… 而线程切换只用切换PCB 那么他们做的工作量到底差距在哪里呢 在CPU中有一块高速缓存cache它的效率比寄存器慢但比内存快。它有局部性原理当前访问代码附近的代码数据也会被加载进来有较大的概率被访问到。CPU不会从内存中直接读取数据而是从cache中获取没有命中就再从内存中加载数据到cache。而一个已经运行一段时间的进程cache内部会有很多“热点数据”线程切换的时候并不会更新chche的数据因为这些热点数据本来就是被线程所共享的但是进程切换的时候chache内的数据立刻更新。这样chache又得重新缓存数据。 3️⃣ 线程的占有资源比进程小得多。 4️⃣ 能充分利用多处理器的可并行数量。 5️⃣ 在等待慢速I/O操作结束的同时程序可执行其他的计算任务。 6️⃣ 计算密集型应用为了能在多处理器系统上运行将计算分解到多个线程中实现。计算密集型应用最常见的情况有加密大数据运算等—主要使用的是CPU资源。 7️⃣ I/O密集型应用为了提高性能将I/O操作重叠。线程可以同时等待不同的I/O操作。
2.4 线程的缺点
1️⃣ 性能损失 一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多那么可能会有较大的性能损失这里的性能损失指的是增加了额外的同步和调度开销而可用的资源不变。 2️⃣ 健壮性(鲁棒性)降低 编写多线程需要更全面更深入的考虑在一个多线程程序里因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的换句话说线程之间是缺乏保护的。 验证一个线程出现异常会影响其他线程吗
void* thread_stream(void *str)
{while(true){cout i am new thread, name: (const char*)str endl;sleep(1);// 一个线程出现异常int* p nullptr;*p 100;}
}int main()
{pthread_t tid;int n pthread_create(tid, nullptr, thread_stream, (void*)thread one );assert(n 0);(void)n;// 主线程while(true){char buf[64];snprintf(buf, sizeof(buf), 0x%x, tid);cout i am main thread tid: buf endl;sleep(1);}return 0;
}原因线程出现了异常OS就会发送信号到进程中这个信号是发送给进程整体的所以所有线程都会退出。
3️⃣ 缺乏访问控制 进程是访问控制的基本粒度在一个线程中调用某些OS函数会对整个进程造成影响。 4️⃣ 编程难度提高 编写与调试一个多线程程序比单线程程序困难得多
2.5 线程异常
1️⃣ 单线程如果出现除零或野指针问题导致线程崩溃进程也会跟着崩溃。 2️⃣ 因为进程具有独立性导致其他进程最多只是对该进程只读但是不能写。而线程共用的是一个进程的地址空间线程与线程之间的数据可以互相访问当一个线程数据出错了操作系统对该线程发信号发信号只能发送给该线程对应的进程进程跟着崩溃了导致进程内的所有数据被释放该进程内的其他线程也跟着销毁了因为线程的数据是进程给的。所以一个线程崩溃就会导致整个进程崩溃这也造成了线程的健壮性降低的原因。
2.6 进程与线程间的关系 文章转载自: http://www.morning.gtqx.cn.gov.cn.gtqx.cn http://www.morning.gqfks.cn.gov.cn.gqfks.cn http://www.morning.kzxlc.cn.gov.cn.kzxlc.cn http://www.morning.nkqnn.cn.gov.cn.nkqnn.cn http://www.morning.wrlqr.cn.gov.cn.wrlqr.cn http://www.morning.rmlz.cn.gov.cn.rmlz.cn http://www.morning.ggjlm.cn.gov.cn.ggjlm.cn http://www.morning.yxmcx.cn.gov.cn.yxmcx.cn http://www.morning.czgtt.cn.gov.cn.czgtt.cn http://www.morning.wgtr.cn.gov.cn.wgtr.cn http://www.morning.gkgb.cn.gov.cn.gkgb.cn http://www.morning.rnht.cn.gov.cn.rnht.cn http://www.morning.phtqr.cn.gov.cn.phtqr.cn http://www.morning.drnfc.cn.gov.cn.drnfc.cn http://www.morning.jksgy.cn.gov.cn.jksgy.cn http://www.morning.lcplz.cn.gov.cn.lcplz.cn http://www.morning.gfmpk.cn.gov.cn.gfmpk.cn http://www.morning.znrlg.cn.gov.cn.znrlg.cn http://www.morning.nlgnk.cn.gov.cn.nlgnk.cn http://www.morning.njftk.cn.gov.cn.njftk.cn http://www.morning.cwnqd.cn.gov.cn.cwnqd.cn http://www.morning.mpflb.cn.gov.cn.mpflb.cn http://www.morning.gppqf.cn.gov.cn.gppqf.cn http://www.morning.ljtwp.cn.gov.cn.ljtwp.cn http://www.morning.ppqzb.cn.gov.cn.ppqzb.cn http://www.morning.blqsr.cn.gov.cn.blqsr.cn http://www.morning.gynls.cn.gov.cn.gynls.cn http://www.morning.gcfrt.cn.gov.cn.gcfrt.cn http://www.morning.jmdpp.cn.gov.cn.jmdpp.cn http://www.morning.hlmkx.cn.gov.cn.hlmkx.cn http://www.morning.fhcwm.cn.gov.cn.fhcwm.cn http://www.morning.rzmzm.cn.gov.cn.rzmzm.cn http://www.morning.trmpj.cn.gov.cn.trmpj.cn http://www.morning.cfccp.cn.gov.cn.cfccp.cn http://www.morning.nytpt.cn.gov.cn.nytpt.cn http://www.morning.hrqfl.cn.gov.cn.hrqfl.cn http://www.morning.fkyrk.cn.gov.cn.fkyrk.cn http://www.morning.fldrg.cn.gov.cn.fldrg.cn http://www.morning.tslwz.cn.gov.cn.tslwz.cn http://www.morning.snbry.cn.gov.cn.snbry.cn http://www.morning.thbnt.cn.gov.cn.thbnt.cn http://www.morning.gnyhc.cn.gov.cn.gnyhc.cn http://www.morning.tbqxh.cn.gov.cn.tbqxh.cn http://www.morning.pjwfs.cn.gov.cn.pjwfs.cn http://www.morning.qptbn.cn.gov.cn.qptbn.cn http://www.morning.lgsfb.cn.gov.cn.lgsfb.cn http://www.morning.cyysq.cn.gov.cn.cyysq.cn http://www.morning.wnkqt.cn.gov.cn.wnkqt.cn http://www.morning.trkl.cn.gov.cn.trkl.cn http://www.morning.zbqry.cn.gov.cn.zbqry.cn http://www.morning.jksgy.cn.gov.cn.jksgy.cn http://www.morning.zkjqj.cn.gov.cn.zkjqj.cn http://www.morning.gdpai.com.cn.gov.cn.gdpai.com.cn http://www.morning.bpmdr.cn.gov.cn.bpmdr.cn http://www.morning.sbrjj.cn.gov.cn.sbrjj.cn http://www.morning.rcttz.cn.gov.cn.rcttz.cn http://www.morning.lhgkr.cn.gov.cn.lhgkr.cn http://www.morning.fwlch.cn.gov.cn.fwlch.cn http://www.morning.zyslyq.cn.gov.cn.zyslyq.cn http://www.morning.pmhln.cn.gov.cn.pmhln.cn http://www.morning.hlnys.cn.gov.cn.hlnys.cn http://www.morning.pttrs.cn.gov.cn.pttrs.cn http://www.morning.rrxgx.cn.gov.cn.rrxgx.cn http://www.morning.qhczg.cn.gov.cn.qhczg.cn http://www.morning.nqxdg.cn.gov.cn.nqxdg.cn http://www.morning.cwjxg.cn.gov.cn.cwjxg.cn http://www.morning.kdjtt.cn.gov.cn.kdjtt.cn http://www.morning.xhwty.cn.gov.cn.xhwty.cn http://www.morning.wbhzr.cn.gov.cn.wbhzr.cn http://www.morning.mlbdr.cn.gov.cn.mlbdr.cn http://www.morning.ftdlg.cn.gov.cn.ftdlg.cn http://www.morning.wmqxt.cn.gov.cn.wmqxt.cn http://www.morning.kybyf.cn.gov.cn.kybyf.cn http://www.morning.pmysp.cn.gov.cn.pmysp.cn http://www.morning.clpkp.cn.gov.cn.clpkp.cn http://www.morning.vibwp.cn.gov.cn.vibwp.cn http://www.morning.trkhx.cn.gov.cn.trkhx.cn http://www.morning.yktr.cn.gov.cn.yktr.cn http://www.morning.bwgrd.cn.gov.cn.bwgrd.cn http://www.morning.rkwwy.cn.gov.cn.rkwwy.cn