当前位置: 首页 > news >正文

黄埔商城网站建设上海园区虚拟地址一览表

黄埔商城网站建设,上海园区虚拟地址一览表,北京网站建设佳v询 lotlek 能上词,公众号投票怎么制作# 干了这碗鸡汤#xff01;我急切地盼望着可以经历一场放纵的快乐#xff0c;纵使巨大的悲哀将接踵而至#xff0c;我也在所不惜。-- 太宰治 《人间失格》大家好#xff0c;这里是周日凌晨4点#xff0c;仍在笔耕不辍的程序喵大人。下面隆重推出我呕心沥血#xff0c;耗时… # 干了这碗鸡汤我急切地盼望着可以经历一场放纵的快乐纵使巨大的悲哀将接踵而至我也在所不惜。 -- 太宰治 《人间失格》大家好这里是周日凌晨4点仍在笔耕不辍的程序喵大人。下面隆重推出我呕心沥血耗时半个月完成的精心力作01什么是进程标准定义进程是一个具有一定独立功能的程序在一个数据集合上依次动态执行的过程。进程是一个正在执行程序的实例包括程序计数器、寄存器和程序变量的当前值。简单来说进程就是一个程序的执行流程内部保存程序运行所需的资源。在操作系统中可以有多个进程在运行可对于CPU来说同一时刻一个CPU只能运行一个进程但在某一时间段内CPU将这一时间段拆分成更短的时间片CPU不停的在各个进程间游走这就给人一种并行的错觉像CPU可以同时运行多个进程一样这就是伪并行。02   进程和程序有什么联系一个进程是某种类型的一个活动它有程序、输入、输出以及状态。单个处理器可以被若干进程共享它使用某种调度算法决定何时停止一个进程的工作并转而为另一个进程提供服务。程序是产生进程的基础程序的每次运行产生不同的进程进程是程序功能的体现通过多次执行一个程序可对应多个进程通过调用关系一个进程可包括多个程序03 进程和程序有什么区别进程是动态的程序是静态的程序是有序代码的集合进程是程序的执行。进程是暂时的程序是永久的进程是一个状态变化的过程程序可长久保存。进程和程序的组成不同进程的组成包括程序、数据和进程控制块进程状态信息。04    进程有什么特点动态性可动态的创建和结束进程并发性可以被独立的调度并占用处理机并发运行独立性不同进程的工作不相互影响制约性因访问共享资源或进程间同步而产生制约05    进程如何创建有什么事件会触发进程的创建呢系统初始化当启动操作系统时通常会创建很多进程有些是同用户交互并替他们完成工作的前台进程其它的都是后台进程后台进程和特定用户没有关系但也提供某些专门的功能例如接收邮件等这种功能的进程也称为守护进程。计划任务是个典型的守护进程它每分钟运行一次来检查是否有工作需要它完成。如果有工作要做它就会完成此工作然后进入休眠状态直到下一次检查时刻的到来。正在运行的程序执行了创建进程的系统调用在一个进程中又创建了一个新的进程这种情况很常见。用户请求创建一个新进程这种情况相信每个人都见过用电脑时双击某个应用图标就会有至少一个进程被创建。一个批处理作业的初始化这种情形不常见仅在大型机的批处理系统中应用用户在这种系统中提交批处理作业在操作系统认为有资源可运行另一个作业时它创建一个新的进程并运行其输入队列中的下一个作业。归根到底在UNIX系统中只有fork系统调用才可以创建新进程使用方式如下#include stdio.h #include unistd.h int main() {pid_t id fork();if (id 0) {perror(fork\n);} else if (id 0) { // 子进程printf(子进程\n);} else { // 父进程printf(父进程\n);}return 0; } 进程创建之后父子进程都有各自不同的地址空间其中一个进程在其地址空间的修改对另一个进程不可见。子进程的初始化空间是父进程的一个副本这里涉及两个不同地址空间不可写的内存区是共享的某些UNIX的实现使程序正文在两者间共享因为它是不可修改的。还有一种写时复制共享技术子进程共享父进程的所有内存一旦两者之一想要修改部分内存则这块内存被复制确保修改发生在当前进程的私有内存区域。06   进程为何终止有什么事件会触发进程的终止呢正常退出自愿进程完成了工作正常终止UNIX中退出进程的系统调用是exit。出错退出自愿进程发现了错误而退出。可以看如下代码#include stdio.h #include stdlib.h void Func() {if (error) { // 有错误就退出程序exit(1);} }int main() {Func(); } 严重错误非自愿进程发生了严重的错误而不得不退出通常是程序的错误导致例如执行了一条非法指令引用不存在的内存或者除数是0等出现这些错误时进程默认会退出。而有些时候如果用户想自行处理某种类型的错误发生不同类型错误时进程会收到不同类型的信号用户注册处理不同信号的函数即可。被其它进程杀死非自愿其它进程执行kill系统调用通知操作系统杀死某个进程。07操作系统如何进行进程管理这里就不得不提到一个数据结构进程控制块PCB操作系统为每个进程都维护一个PCB用来保存与该进程有关的各种状态信息。进程可以抽象理解为就是一个PCBPCB是进程存在的唯一标志操作系统用PCB来描述进程的基本情况以及运行变化的过程进程的任何状态变化都会通过PCB来体现。PCB包含进程状态的重要信息包括程序计数器、堆栈指针、内存分配状况、所打开文件的状态、账号和调度信息以及其它在进程由运行态转换到就绪态或阻塞态时必须保存的信息从而保证该进程随后能再次启动就像从未中断过一样。后一小节会具体介绍PCB。提到进程管理有一个概念我们必须要知道就是中断向量中断向量是指中断服务程序的入口地址。一个进程在执行过程中可能会被中断无数次但是每次中断后被中断的进程都要返回到与中断发生前完全相同的状态。中断发生后操作系统最底层做了什么呢1硬件压入堆栈程序计数器等2硬件从中断向量装入新的程序计数器3汇编语言过程保存寄存器值4汇编语言过程设置新的堆栈5C中断服务例程运行典型的读和缓冲输入6调度程序决定下一个将运行的进程7C过程返回到汇编代码8汇编语言过程开始运行新的当前进程。08进程控制块中存储了什么信息进程标识信息如本进程的标识本进程的父进程标识用户标识等。处理机状态信息保护区用于保存进程的运行现场信息用户可见寄存器用户程序可以使用的数据地址等寄存器控制和状态寄存器程序计数器程序状态字栈指针过程调用、系统调用、中断处理和返回时需要用到它进程控制信息调度和状态信息用于操作系统调度进程使用进程间通信信息为支持进程间与通信相关的各种标识、信号、信件等这些信息存在接收方的进程控制块中存储管理信息包含有指向本进程映像存储空间的数据结构进程所用资源说明由进程打开使用的系统资源如打开的文件等有关数据结构连接信息进程可以连接到一个进程队列中或连接到相关的其他进程的PCB09   进程如何进行生命周期管理进程创建创建进程有三个主要事件系统初始化用户请求创建一个新进程一个正在运行的进程执行创建进程的系统调用进程运行内核选择一个就绪的进程让它占用处理机并运行这里就涉及到了进程的调度策略选择哪个进程调度为什么选择调度这个进程呢莫慌下面会介绍哈进程等待在以下情况下进程会等待阻塞请求并等待系统服务无法马上完成启动某种操作无法马上完成需要的数据没有到达。注意进程只能自己阻塞自己因为只有进程自身才能知道何时需要等待某种事件的发生。进程唤醒进程只能被别的进程或操作系统唤醒唤醒进程的原因有被阻塞进程需要的资源可被满足被阻塞进程等待的事件到达将该进程的PCB插入到就绪队列进程结束在以下四种情况下进程会结束自愿型正常退出自愿型错误退出强制型致命错误退出强制型被其它进程杀死退出10进程都有什么状态不同系统设置的进程状态是不同的多数系统中的进程在生命结束前有三种基本状态进程只会处于三种基本状态之一运行状态进程正在处理机上运行时就处在运行状态该时刻进程时钟占用着CPU就绪状态万事俱备只欠东风进程已经获得了除处理机之外的一切所需资源一旦得到处理机就可以运行就绪态中的进程其实可以运行但因为其它进程正在占用着CPU而暂时停止运行等待状态阻塞状态进程正在等待某一事件而暂停运行等待某个资源或者等待输入输出完成。除非某种外部事件发生否则阻塞态的进程不能运行进程状态变化图如下在操作系统发现进程不能继续运行下去时进程因为等待输入而被阻塞进程从运行态转换到阻塞态调度程序选择了另一个进程执行时当前程序就会从运行态转换到就绪态被调度程序选择的程序会从就绪态转换到运行态当阻塞态的进程等待的一个外部事件发生时就会从阻塞态转换到就绪态此时如果没有其他进程运行时则立刻从就绪态转换到运行态某些系统设置下进程还会有其它状态创建状态进程正在被创建还没被转到就绪状态之前的状态结束状态进程正在从系统中消失时的状态。有些与进程管理相关的系统调用读者有必要了解一下pidfork(); // 创建一个与父进程一样的子进程 pidwaitpid(); // 等待子进程终止 sexecve(); // 替换进程的核心映像 exit(); // 终止进程运行并返回状态值 ssigaction(); // 定义信号处理的动作 ssigprocmask(); // 检查或更换信号掩码 ssigpending(); // 获得阻塞信号集合 ssigsuspend(); // 替换信号掩码或挂起进程 alarm(); // 设置定时器 pause(); // 挂起调用程序直到下一个信号出现 11什么是进程挂起为什么会出现进程挂起进程挂起就是为了合理且充分的利用系统资源把一个进程从内存转到外存。进程在挂起状态时意味着进程没有占用内存空间处在挂起状态的进程映射在磁盘上。进程挂起通常有两种状态阻塞挂起状态进程在外存并等待某事件的出现就绪挂起状态进程在外存但只要进入内存即可运行。有什么与进程挂起相关的状态转换进程挂起可能有以下几种情况阻塞到阻塞挂起没有进程处于就绪状态或就绪进程要求更多内存资源时会进行这种转换以提交新进程或运行就绪进程就绪到就绪挂起当有高优先级阻塞进程或低优先级就绪进程时系统会选择挂起低优先级就绪进程运行到就绪挂起对于抢占式分时系统当有高优先级阻塞挂起进程因事件出现而进入就绪挂起时系统可能会把运行进程转到就绪挂起状态阻塞挂起到就绪挂起当有阻塞挂起进程有相关事件出现时系统会把阻塞挂起进程转换为就绪挂起进程。有进程挂起那就有进程解挂指一个进程从外存转到内存相关状态有就绪挂起到就绪没有就绪进程或就绪挂起进程优先级高于就绪进程时就会进行这种转换阻塞挂起到阻塞当一个进程释放足够内存时系统会把一个高优先级阻塞挂起进程转换为阻塞进程。12   什么是进程调度操作系统对于进程调度都有什么策略当系统中有多个进程同时竞争CPU如果只有一个CPU可用那同一时刻只会有一个进程处于运行状态操作系统必须要选择下一个要运行的是哪个进程在操作系统中完成选择工作的这部分称为调度程序该程序使用的算法称作调度算法。什么时候进行调度系统调用创建一个新进程后需要决定是运行父进程还是运行子进程一个进程退出时需要做出调度决策需要决定下一个运行的是哪个进程当一个进程阻塞在I/O和信号量或者由于其它原因阻塞时必须选择另一个进程运行当一个I/O中断发生时如果中断来自IO设备而该设备现在完成了工作某些被阻塞的等待该IO的进程就成为可运行的就绪进程了是否让新就绪的进程运行或者让中断发生时运行的进程继续运行或者让某个其它进程运行这就取决于调度程序的抉择了。调度算法可以分类非抢占式调度算法挑选一个进程然后让该进程运行直至被阻塞或者直到该进程自动释放CPU即使该进程运行了若干个小时它也不会被强迫挂起。这样做的结果是在时钟中断发生时不会进行调度在处理完时钟中断后如果没有更高优先级的进程等待则被中断的进程会继续执行。简单来说调度程序必须等待事件结束。非抢占方式引起进程调度的条件进程执行结束或发生某个事件而不能继续执行正在运行的进程因有I/O请求而暂停执行进程通信或同步过程中执行了某些原语操作wait、block等抢占式调度算法挑选一个进程并且让该进程运行某个固定时段的最大值。如果在该时段结束时该进程仍在运行它就被挂起而调度程序挑选另一个进程运行进行抢占式调度处理需要在时间间隔的末端发生时钟中断以便CPU控制返回给调度程序如果没有可用的时钟那么非抢占式调度就是唯一的选择。简单来说就是当前运行的进程在事件没结束时就可以被换出防止单一进程长时间独占CPU资源。下面会介绍很多抢占式调度算法优先级算法、短作业优先算法、轮转算法等。调度策略不同系统环境下有不同的调度策略算法。调度算法也是有KPI的对调度算法首先提的需求就是公平调度算法需要给每个进程公平的CPU份额相似的进程应该得到相似的服务对一个进程给予较其它等价的进程更多的CPU时间是不公平的被普通水平的应届生工资倒挂也是不公平的执行力每一个策略必须强制执行需要保证规定的策略一定要被执行。平衡需要保证系统的所有部分尽可能都忙碌但是因为不同的应用有不同的目标不同的系统中调度程序的优化也是不同的大体可以分为三种环境批处理系统批处理系统的管理者为了掌握系统的工作状态主要关注三个指标吞吐量是系统每小时完成的作业数量周转时间指从一个作业提交到完成的平均时间CPU利用率尽可能让CPU忙碌但又不能过量调度算法先来先服务先来后到嘛就像平时去商店买东西需要排队一样使用该算法进程按照它们请求CPU的顺序来使用CPU该算法最大的优点就是简单易于实现太容易的不一定是好的该算法也有很大的缺点平均等待时间波动较大时间短的任务可能排队排在了时间长的任务后面。举个生活中的例子排着队去取快递如果每个人都很快取出来快递还好如果前面有几个人磨磨唧唧到快递柜前才拿出手机打开app再找半分钟它的取件码就会严重拖慢后面的人取快递的速度同理排着队的进程如果每个进程都很快就运行完还好如果其中有一个得到了CPU的进程运行时候磨磨唧唧很长时间都运行不完那后面的进程基本上就没有机会运行了最短作业优先该调度算法是非抢占式的算法每个进程执行期间不会被打断每次都选择执行时间最短的进程来调度但问题来了操作系统怎么可能知道进程具体的执行时间呢所以该算法注定是基于预测性质的理想化算法而且有违公平性而且可能导致运行时间长的任务得不到调度。最短剩余时间优先该调度算法是抢占式的算法是最短作业优先的抢占版本在进程运行期间如果来了个更短时间的进程那就转而去把CPU时间调度给这个更短时间的进程它的缺点和最短作业优先算法类似。交互式系统对于交互系统最重要的指标就是响应时间和均衡性啦响应时间一个请求被提交到产生第一次响应所花费的时间。你给别人发微信别人看后不回复你或者几个小时后才回复你你是什么感受这还是交互式吗均衡性减少平均响应时间的波动。需要符合固有期望和预期你给别人发微信他有时候秒回复有时候几个小时后才回复。在交互式系统中可预测性比高差异低平均更重要。调度算法轮转调度每个进程被分配一个时间段称为时间片即CPU做到雨露均沾轮流翻各个进程的牌子这段时间宠幸进程A下一段时间宠幸进程B再下一段时间宠幸进程C确保每个进程都可以获得CPU时间如果CPU时间特别短的话在外部看来像是同时宠幸了所有进程一样。那么问题来了这个时间片究竟多长时间好呢如果时间片设的太短会导致过多的进程切换频繁的上下文切换会降低CPU效率而如果时间片设的太长又可能对短的交互请求的响应时间变长通常将时间片设为20-50ms是个比较合理的折中大佬们的经验规则时维持上下文切换的开销处于1%以内。优先级调度上面的轮转调度算法是默认每个进程都同等重要都有相同优先级然而有时候进程需要设置优先级例如某些播放视频的前台进程可以优先于某些收发邮件的后台守护进程被调度在优先级调度算法中每个优先级都有相应的队列队列里面装着对应优先级的进程首先在高优先级队列中进行轮转调度当高优先级队列为空时转而去低优先级队列中进行轮转调度如果高优先级队列始终不为空那么低优先级的进程很可能就会饥饿到很久不能被调度。多级队列多级队列算法与优先级调度算法不同优先级算法中每个进程分配的是相同的时间片而在多级队列算法中不同队列中的进程分配给不同的时间片当一个进程用完分配的时间片后就移动到下一个队列中这样可以更好的避免上下文频繁切换。举例有一个进程需要100个时间片如果每次调度都给分配一个时间片则需要100次上下文切换这样CPU运行效率较低通过多级队列算法可以考虑最开始给这个进程分配1个时间片然后被换出下次分给它2个时间片再换出之后分给它4、8、16、64个时间片这样分配的话该进程只需要7次交换就可以运行完成相比100次上下文切换运行效率高了不少但顾此就会失彼那些需要交互的进程得到响应的速度就会下降。最短进程优先交互式系统中应用最短进程优先算法其实是非常适合的每次都选择执行时间最短的进程进行调度这样可以使任务的响应时间最短但这里有个任务还没有运行呢我怎么知道进程的运行时间呢根本没办法非常准确的再当前可运行进程中找出最短的那个进程。有一种办法就是根据进程过去的行为进行预测但这能证明是个好办法吗保证调度这种调度算法就是向用户做出明确的可行的性能保证然后去实现它。一种很实际的可实现的保证就是确保N个用户中每个用户都获得CPU处理能力的1/N类似的保证N个进程中每个进程都获得1/N的CPU时间。彩票调度彩票调度算法基本思想是为进程提供各种资源CPU时间的彩票一旦需要做出调度决策时就随机抽出一张彩票拥有该彩票的进程获得该资源很明显拥有彩票越多的进程获得资源的可能性越大。该算法在程序喵看来可以理解为股票算法将CPU的使用权分成若干股假设共100股分给了3个进程给这些进程分别分配20、30、50股那么它们大体上会按照股权比例203050划分CPU的使用。公平分享调度假设有系统两个用户用户1启动了1个进程用户2启动了9个进程如果使用轮转调度算法那么用户1将获得10%的CPU时间用户2将获得90%的CPU时间这对用户来说公平吗如果给每个用户分配50%的CPU时间那么用户2中的进程获得的CPU时间明显比用户1中的进程短这对进程来说公平吗这就取决于怎么定义公平啦实时系统实时系统顾名思义最关键的指标当然是实时啦满足截止时间需要在规定deadline前完成作业可预测性可预测性是指在系统运行的任何时刻在任何情况下实时系统的资源调配策略都能为争夺资源的任务合理的分配资源使每个实时任务都能得到满足。调度算法分类硬实时必须在deadline之前完成工作如果delay可能会发生灾难性或发生严重的后果软实时必须在deadline之前完成工作但如果偶尔delay了也可以容忍。调度算法单调速率调度采用抢占式、静态优先级的策略调度周期性任务。每个任务最开始都被配置好了优先级当较低优先级的进程正在运行并且有较高优先级的进程可以运行时较高优先级的进程将会抢占低优先级的进程。在进入系统时每个周期性任务都会分配一个优先级周期越短优先级越高。这种策略的理由是更频繁的需要CPU的任务应该被分配更高的优先级。最早截止时间调度根据截止时间动态分配优先级截止时间越早的进程优先级越高。该算法中当一个进程可以运行时它应该向操作系统通知截止时间根据截止时间的早晚系统会为该进程调整优先级以便满足可运行进程的截止时间要求。它与单调速率调度算法的区别就是一个是静态优先级一个是动态优先级。如何配置调度策略调度算法有很多种各有优缺点操作系统自己很少能做出最优的选择那么可以把选择权交给用户由用户根据实际情况来选择适合的调度算法这就叫策略与机制分离调度机制位于内核调度策略由用户进程决定将调度算法以某种形式参数化由用户进程来选择参数从而决定内核使用哪种调度算法。13 操作系统怎么完成进程调度进程的每次变化都会有相应的状态而操作系统维护了一组状态队列表示系统中所有进程的当前状态不同的状态有不同的队列有就绪队列阻塞队列等每个进程的PCB都根据它的状态加入到相应的队列中当一个进程的状态发生变化时它的PCB会从一个状态队列中脱离出来加入到另一个状态队列。注意图中同一种状态为什么有多个队列呢因为进程有优先级概念相同状态的不同队列的优先级不同。14    什么是线程线程是进程当中的一条执行流程这几乎就是进程的定义一个进程内可以有多个子执行流程即线程。可以从两个方面重新理解进程从资源组合的角度进程把一组相关的资源组合起来构成一个资源平台环境包括地址空间代码段、数据段打开的文件等各种资源从运行的角度代码在这个资源平台上的执行流程然而线程貌似也是这样但是进程比线程多了资源内容列表样式那就有一个公式进程 线程 共享资源15   为什么使用线程因为要并发编程在许多情形中同时发生着许多活动而某些活动有时候会被阻塞通过将这些活动分解成可以准并行运行的多个顺序流程是必须的而如果使用多进程方式进行并发编程进程间的通信也很复杂并且维护进程的系统开销较大创建进程时分配资源建立PCB撤销进程时回收资源撤销PCB进程切换时保存当前进程的状态信息。所以为了使并发编程的开销尽量小所以引入多线程编程可以并发执行也可以共享相同的地址空间。并行实体拥有共享同一地址空间和所有可用数据的能力这是多进程模型所不具备的能力。使用线程有如下优点可以多个线程存在于同一个进程中各个线程之间可以并发的执行各个线程之间可以共享地址空间和文件等资源线程比进程更轻量级创建线程撤销线程比创建撤销进程要快的多在许多系统中创建一个线程速度是创建一个进程速度的10-100倍。如果多个线程是CPU密集型的并不能很好的获得更好的性能但如果多个线程是IO密集型的线程存在着大量的计算和大量的IO处理有多个线程允许这些活动彼此重叠进行从而会加快整体程序的执行速度。但也有缺点一旦一个线程崩溃会导致其所属进程的所有线程崩溃。由于各个线程共享相同的地址空间那么读写数据可能会导致竞争关系因此对同一块数据的读写需要采取某些同步机制来避免线程不安全问题。16    什么时候用进程、线程进程是资源分配单位线程是CPU调度单位进程拥有一个完整的资源平台而线程只独享必不可少的资源如寄存器和栈线程同样具有就绪阻塞和执行三种基本状态同样具有状态之间的转换关系线程能减少并发执行的时间和空间开销线程的创建时间比进程短线程的终止时间比进程短同一进程内的线程切换时间比进程短由于同一进程的各线程间共享内存和文件资源可直接进行不通过内核的通信结论可以在强调性能时候使用线程如果追求更好的容错性可以考虑使用多进程google浏览器据说就是用的多进程编程。在多CPU系统中多线程是有益的在这样的系统中通常情况下可以做到真正的并行。C/C中如何使用多线程编程POSIX使用如下线程封装函数来操作线程pthread_create 创建一个新线程 pthread_exit 结束调用的线程 pthread_join 等待一个特定的线程退出 pthread_yield 释放CPU来运行另外一个线程 pthread_attr_init 创建并初始化一个线程的属性结构 pthread_attr_destroy 删除一个线程的属性结构 后两个函数是有关线程属性的调用。pthread_attr_init建立关联一个线程的属性结构并初始化成默认值这些值优先级等可以通过修改属性结构中的对应值来改变pthread_attr_destroy会删除一个线程的属性结构释放它占用的内存它不会影响调用它的线程线程依然会继续存在。C中有std::thread和async可以很方便的操作多线程示例代码如下void F() {cout a endl; }int main() {std::thread r(F);r.detach();std::this_thread::sleep_for(std::chrono::seconds(20));return 0; } 想了解更多关于C线程相关的知识点可以看  c11新特性所有知识点都在这了17   线程是如何实现的线程的实现可分为用户线程和内核线程用户线程在用户空间实现的线程机制它不依赖于操作系统的内核由一组用户级的线程库函数来完成线程的管理包括进程的创建终止同步和调度等。用户线程有如下优点由于用户线程的维护由相应进程来完成通过线程库函数不需要操作系统内核了解内核了解用户线程的存在可用于不支持线程技术的多进程操作系统。每个进程都需要它自己私有的线程控制块列表用来跟踪记录它的各个线程的状态信息PC栈指针寄存器TCB由线程库函数来维护用户线程的切换也是由线程库函数来完成无需用户态/核心态切换所以速度特别快允许每个进程拥有自定义的线程调度算法但用户线程也有缺点阻塞性的系统调用如何实现如果一个线程发起系统调用而阻塞则整个进程在等待。当一个线程开始运行后除非它主动交出CPU的使用权否则它所在进程当中的其它线程将无法运行由于时间片分配给进程与其它进程比在多线程执行时每个线程得到的时间片较少执行会较慢内核线程是指在操作系统的内核中实现的一种线程机制由操作系统的内核来完成线程的创建终止和管理。特点在支持内核线程的操作系统中由内核来维护进程和线程的上下文信息PCB TCB线程的创建终止和切换都是通过系统调用内核函数的方式来进行由内核来完成因此系统开销较大在一个进程当中如果某个内核线程发起系统调用而被阻塞并不会影响其它内核线程的运行时间片分配给线程多线程的进程获得更多CPU时间tips由于在内核中创建或撤销线程的代价比较大某些系统采取复用的方式回收线程当某个线程被撤销时就把它标记不可运行但是内核数据结构没有受到任何影响如果后续又需要创建一个新线程时就重新启动被标记为不可运行的旧线程从而节省一些开销。注意尽管使用内核线程可以解决很多问题但还有些问题例如当一个多线程的进程创建一个新的进程时会发生什么新进程是拥有与原进程相同数量的线程还是只有一个线程在很多情况下最好的选择取决于进程计划下一步做什么如果它要调用exec启动一个新程序或许一个线程正合适但如果它继续运行那么最好复制所有的线程。轻量级进程它是内核支持的用户线程模型一个进程可以有多个轻量级进程每个轻量级进程由一个单独的内核线程来支持。在Linux下是没有真正的线程的它所谓的线程其实就是使用进程来实现的就是所谓的轻量级进程其实就是进程都是通过clone接口调用创建的只不过两者传递的参数不同通过参数决定子进程和父进程共享的资源种类和数量进而有了普通进程和轻量级进程的区别。18    什么是上下文切换上下文切换指的是操作系统停止当前运行进程从运行状态改变成其它状态并且调度其它进程就绪态转变成运行状态。操作系统必须在切换之前存储许多部分的进程上下文必须能够在之后恢复他们所以进程不能显示它曾经被暂停过同时切换上下文这个过程必须快速因为上下文切换操作是非常频繁的。那上下文指的是什么呢指的是任务所有共享资源的工作现场每一个共享资源都有一个工作现场包括用于处理函数调用、局部变量分配以及工作现场保护的栈顶指针和用于指令执行等功能的各种寄存器。注意这里所说的进程切换导致上下文切换其实不太准确准确的说应该是任务的切换导致上下文切换这里的任务可以是进程也可以是线程准确的说线程才是CPU调度的基本单位但是因为各个资料都这么解释上下文切换所以上面也暂时这么介绍只要读者心里有这个概念就好。19   进程间通信有几种方式由于各个进程不共享相同的地址空间任何一个进程的全局变量在另一个进程中都不可见所以如果想要在进程之间传递数据就需要通过内核在内核中开辟出一块区域该区域对多个进程都可见即可用于进程间通信。有读者可能有疑问了文件方式也是进程间通信啊也要在内核开辟区域吗这里说的内核区域其实是一段缓冲区文件方式传输数据也有内核缓冲区的参与零拷贝除外。如何开辟这种公共区域来进行进程间通信呢匿名管道匿名管道就是pipepipe只能在父子进程间通信而且数据只能单向流动半双工通信。使用方式1父进程创建管道会得到两个文件描述符分别指向管道的两端2父进程创建子进程从而子进程也有两个文件描述符指向同一管道3父进程可写数据到管道子进程就可从管道中读出数据从而实现进程间通信下面的示例代码中通过pipe实现了每秒钟父进程向子进程都发送消息的功能。#include stdio.h #include string.h #include unistd.h int main() {int _pipe[2];int ret pipe(_pipe);if (ret 0) {perror(pipe\n);}pid_t id fork();if (id 0) {perror(fork\n);} else if (id 0) { // 子进程close(_pipe[1]);int j 0;char _mesg[100];while (j 100) {memset(_mesg, \0, sizeof(_mesg));read(_pipe[0], _mesg, sizeof(_mesg));printf(%s\n, _mesg);j;}} else { // 父进程close(_pipe[0]);int i 0;char *mesg NULL;while (i 100) {mesg 父进程来写消息了;write(_pipe[1], mesg, strlen(mesg) 1);sleep(1);i;}}return 0;} 我们平时也经常使用关于管道的命令行ls | less 该命令行的流向图如下1创建管道2为ls创建一个进程设置stdout为管理写端3为less创建一个进程设置stdin为管道读端高级管道通过popen将另一个程序当作一个新的进程在当前进程中启动它算作当前进程的子进程高级管道只能用在有亲缘关系的进程间通信这种亲缘关系通常指父子进程下面的GetCmdResult函数可以获取某个Linux命令执行的结果实现方式就是通过popen。std::string GetCmdResult(const std::string cmd, int max_size 10240) {char *data (char *)malloc(max_size);if (data NULL) {return std::string(malloc fail);}memset(data, 0, max_size);const int max_buffer 256;char buffer[max_buffer];// 将标准错误重定向到标准输出FILE *fdp popen((cmd 21).c_str(), r);int data_len 0;if (fdp) {while (!feof(fdp)) {if (fgets(buffer, max_buffer, fdp)) {int len strlen(buffer);if (data_len len max_size) {cout data size larger than max_size;break;}memcpy(data data_len, buffer, len);data_len len;}}pclose(fdp);}std::string ret(data, data_len);free(data);return ret; } 命名管道匿名管道有个缺点就是通信的进程一定要有亲缘关系而命名管道就不需要这种限制。命名管道其实就是一种特殊类型的文件所谓的命名其实就是文件名文件对各个进程都可见通过命名管道创建好特殊文件后就可以实现进程间通信。可以通过mkfifo创建一个特殊的类型的文件参数读者看名字应该就了解一个是文件名一个是文件的读写权限int mkfifo(const char* filename, mode_t mode); 当返回值为0时表示该命名管道创建成功至于如何通信其实就是个读写文件的问题消息队列队列想必大家都知道像FIFO一样这里可以有多个进程写入数据也可以有多个进程从队列里读出数据但消息队列有一点比FIFO还更高级它读消息不一定要使用先进先出的顺序每个消息可以赋予类型可以按消息的类型读取不是指定类型的数据还存在队列中。本质上MessageQueue是存放在内核中的消息链表每个消息队列链表会由消息队列标识符表示这个消息队列存于内核中只有主动的删除该消息队列或者内核重启时消息队列才会被删除。在Linux中消息队列相关的函数调用如下// 创建和访问一个消息队列 int msgget(key_t, key, int msgflg); // 用来把消息添加到消息队列中 int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg); // msg_ptr是结构体数据的指针结构第一个字段要有个类型struct Msg {long int message_type;// 想要传输的数据 }; // 从消息队列中获取消息 int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg); // 用来控制消息队列不同的command参数有不同的控制方式 int msgctl(int msgid, int command, struct msgid_ds *buf); 示例代码如下#include errno.h #include stdio.h #include stdlib.h #include string.h #include sys/msg.h#include chrono #include iostream #include threadusing namespace std;#define BUFFER_SIZ 20typedef struct {long int msg_type;char text[BUFFER_SIZ]; } MsgWrapper;void Receive() {MsgWrapper data;long int msgtype 2;int msgid msgget((key_t)1024, 0666 | IPC_CREAT);if (msgid -1) {cout msgget error \n;return;}while (true) {if (msgrcv(msgid, (void *)data, BUFFER_SIZ, msgtype, 0) -1) {cout error errno endl;}cout read data data.text endl;if (strlen(data.text) 6) { // 发送超过6个字符的数据结束break;}}if (msgctl(msgid, IPC_RMID, 0) -1) {cout msgctl error \n;}cout Receive ok \n; }void Send() {MsgWrapper data;long int msgtype 2;int msgid msgget((key_t)1024, 0666 | IPC_CREAT);if (msgid -1) {cout msgget error \n;return;}data.msg_type msgtype;for (int i 0; i 10; i) {memset(data.text, 0, BUFFER_SIZ);char a a i;memset(data.text, a, 1);if (msgsnd(msgid, (void *)data, BUFFER_SIZ, 0) -1) {cout msgsnd error \n;return;}std::this_thread::sleep_for(std::chrono::seconds(1));}memcpy(data.text, 1234567, 7);if (msgsnd(msgid, (void *)data, BUFFER_SIZ, 0) -1) {cout msgsnd error \n;return;} }int main() {std::thread r(Receive);r.detach();std::thread s(Send);s.detach();std::this_thread::sleep_for(std::chrono::seconds(20));return 0; }输出rootiZuf64idor3ej648ciairaZ:~# ./a.out read data a read data b read data c read data d read data e read data f read data g read data h read data i read data j read data 1234567 Receive ok 代码中为了演示方便使用消息队列进行的线程间通信该代码同样用于进程间通信消息队列的实现依赖于内核的支持上述代码可能在某些系统WSL上不能运行在正常的Ubuntu上可以正常运行。消息队列VS命名管道消息队列命名管道1消息队列收发消息自动保证了同步不需要由进程自己来提供同步方法而命名管道需要自行处理同步问题2消息队列接收数据可以根据消息类型有选择的接收特定类型的数据不需要像命名管道一样默认接收数据。消息队列命名管道消息队列有一个缺点就是发送和接收的每个数据都有最大长度的限制。共享内存可开辟中一块内存用于各个进程间共享使得各个进程可以直接读写同一块内存空间就像线程共享同一块地址空间一样该方式基本上是最快的进程间通信方式因为没有系统调用干预也没有数据的拷贝操作但由于共享同一块地址空间数据竞争的问题就会出现需要自己引入同步机制解决数据竞争问题。共享内存只是一种方式它的实现方式有很多种主要的有mmap系统调用、Posix共享内存以及System V共享内存等。通过这三种“工具”共享地址空间后通信的目的自然就会达到。信号信号也是进程间通信的一种方式信号可以在任何时候发送给某一个进程如果进程当前并未处于执行状态内核将信号保存直到进程恢复到执行态再发送给进程进程可以对信号设置预处理方式如果对信号设置了阻塞处理则信号的传递会被延迟直到阻塞被取消如果进程结束那信号就被丢弃。我们常用的CTRLC和kill等就是信号的一种也达到了进程间通信的目的进程也可以对信号设置signal捕获函数自定义处理逻辑。这种方式有很大的缺点只有通知的作用通知了一下消息的类型但不能传输要交换的任何数据。Linux系统中常见的信号有SIGHUP该信号在用户终端结束时发出通常在中断的控制进程结束时所有进程组都将收到该信号该信号的默认操作是终止进程SIGINT程序终止信号通常的CTRLC产生该信号来通知终止进程SIGQUIT类似于程序错误信号通常的CTRL\产生该信号通知进程退出时产生core文件SIGILL执行了非法指令通常数据段或者堆栈溢出可能产生该信号SIGTRAP供调试器使用由断电指令或其它陷阱指令产生SIGABRT使程序非正常结束调用abort函数会产生该信号SIGBUS非法地址通常是地址对齐问题导致比如访问一个4字节长的整数但其地址不是4的倍数SIGSEGV合理地址的非法访问访问了未分配的内存或者没有权限的内存区域SIGPIPE管道破裂信号socket通信时经常会遇到进程写入了一个无读者的管道SIGALRM时钟定时信号由alarm函数设置的时间终止时产生SIGFPE出现浮点错误比如除0操作SIGKILL杀死进程不能被捕捉和忽略信号量想必大家都听过信号量信号量就是一个特殊的变量程序对其访问都是原子操作每个信号量开始都有个初始值。最简单最常见的信号量是只能取0和1的变量也叫二值信号量。信号量有两个操作P和VP如果信号量变量值大于0则变量值减1如果值为0则阻塞进程V如果有进程阻塞在该信号量上则唤醒阻塞的进程如果没有进程阻塞则变量值加1Q信号量和信号有什么关系A没有任何关系完全是不同的东西。Q信号量与互斥量有什么区别A互斥量用于互斥信号量用于同步互斥指的是某一资源同一时间只允许一个访问者访问但无法限制访问顺序访问是无序的而同步在互斥的基础上可以控制访问者对资源的顺序。套接字就是网络传输不用多说网络通信都可以多机通信呢更不用说进程间通信啦你能看到程序喵的文章也是套接字的功劳。文件显而易见多个进程可以操作同一个文件所以也可以通过文件来进行进程间通信。关于进程和线程的知识点介绍就到这里程序喵为了写本文花费了半月以上时间相信你弄懂这19个问题面试不用愁参考资料https://cloud.tencent.com/developer/article/1339562https://blog.csdn.net/gatieme/article/details/51481863https://blog.csdn.net/sddxqlrjxr/article/details/51249619《现代操作系统》《B站清华操作系统教学视频》《B站哈工大操作系统教学视频》推荐阅读专辑|Linux文章汇总专辑|程序人生专辑|C语言我的知识小密圈嵌入式Linux微信扫描二维码关注我的公众号
http://www.pierceye.com/news/791156/

相关文章:

  • 怎么样做网站徐州市中宇建设工程有限公司网站
  • 网站建站公司官网免费企业网站建设介绍
  • 知名网站建设托管河北建筑工程学院招生信息网
  • 服务器网站建设流程图十堰网站制作公司电话
  • 营销型网站seo开发一个app需要什么技能
  • 网站的欢迎页怎么做织梦网站名称修改
  • 树莓派做博客网站济南抖音推广公司
  • 网站短链接生成济宁网络
  • 组建 网站开发团队交互设计作品集网站
  • 宜春个人网站建设网站建设惠州
  • 医院网站开发兼职wordpress 域名跳转
  • 安监局网站建设wordpress 修改路径
  • 快速搭建网站wordpress成品网站货源入口
  • 信宜手机网站建设公司广州网站建设服务商
  • 网站备案注册3g免费网站制作
  • 做网站需要vps吗建设银行etc的网站是哪个好
  • 网站服务器 2核如何做网站联盟
  • 做空间的网站吗wordpress 视频管理 主题
  • 做外链选择那些网站建网站怎样往网站传视频
  • 网站主机多大车陂手机网站建设报价
  • 网站策划书内容wordpress 一键恢复
  • wordpress+外观+权限seo排名工具
  • 江苏企业网站制作哪家好潍坊网站开发招生信息
  • 建设一个地方门户网站网站名称搜索不到
  • 南江县住房和城乡建设局网站上海seo关键词优化
  • 门窗厂家东莞网站建设湖南健康码
  • 企业网站建设的背景和目的互联网政务服务平台
  • 化州市住房和城乡建设局网站开发网站心得
  • 网站设计制作公司需要什么资质python h5网站开发
  • 广东深圳广东深圳网站建设惠州网站开发公司电话