哪些网站可以免费发布广告合肥百度关键词排名
2026/1/10 2:41:22 网站建设 项目流程
哪些网站可以免费发布广告,合肥百度关键词排名,好玩的传奇,制作公众号开发公司❀保持低旋律节奏-个人主页 专栏链接#xff1a;《C学习》、《Linux学习》 文章目录前置知识1.操作系统中的进程状态和Linux中的进程状态#x1f44d;2.偏移量起始地址 目标地址#x1f44d;3.正式开始剖析#xff01;操作系统内核里面的数据结构那么为什么操作系…❀保持低旋律节奏-个人主页专栏链接《C学习》、《Linux学习》文章目录前置知识1.操作系统中的进程状态和Linux中的进程状态2.偏移量起始地址 目标地址3.正式开始剖析操作系统内核里面的数据结构那么为什么操作系统要这么做 为什么要把内部数据结构设计成这样进程状态1.R运行状态补充——前台进程后台进程2.阻塞状态2.1S可中断睡眠状态2.2D不可中断睡眠状态2.3T停止态2.4t跟踪停止态3.挂起状态僵尸进程和孤儿进程1.僵尸状态和僵尸进程2.孤儿进程前置知识1.操作系统中的进程状态和Linux中的进程状态操作系统中的进程状态Linux中的进程状态结论一操作系统中的进程状态和Linux中的进程状态 个状态之间的联系以及他们之间担任的角色都存在的大同小异的效果而在本章节我们重点要学习linux中的进程状态linux进程状态名称具体含义场景RTAST_RUNNING运行态合并就绪和运行态。要么进程在cpu上执行命令要么在排队等待cpu分配时间片比如死循环程序会一直处于该状态用 ps 命令查看可能显示 R前台运行或 R后台运行。S(TAST_INTERRUPTIBLE)可中断睡眠态因等待某个事件挂起比如键盘输入、等待网络传输数据、在比如文本编辑器。系统中大多数进程平时就处于这个状态。使用kill命令可以唤醒或者终止这个进程D(TAST_UNINTERRUPTIBLE)不可中断睡眠态也叫磁盘睡眠态。进程同样处于睡眠态大多数是在等在磁盘I/o等关键操作完成。核心特点是操作系统也无法杀死他kill -9命令也无法杀死例如向磁盘写入重要数据时候可能就处于该状态T(TAST_STOPPED)停止态进程收到SIGSTOP信号后会被暂停执行直到收到SIGCONT信号才会回复运行比如终端执行kill -SIGSTOP 进程号 就可以让目标进入该状态然后用 kill -SIGCONT 进程号 可恢复t(tracing stop)跟踪停止态和 T 状态类似但专门用于调试场景。当进程被 gdb 等调试工具跟踪时遇到断点就会进入该状态。此状态下进程不能用 SIGCONT 信号唤醒只能通过调试工具的操作如继续执行指令恢复运行。X(TASK_DEAD-EXIT_DEAD) 死亡态进程生命周期的最后阶段代表进程已完全终止正在释放最后的资源这个状态非常短暂用 ps 等命令几乎无法捕捉到资源清理完成后进程就会彻底从系统中消失。Z(TAST_DEAD-EXIT_ZOMBIE)僵尸态进程执行完毕但是父进程没有调用wait()\waitpid()等函数回收它退出的状态信息此时代码和数据已经释放但是 PCB还保留着僵尸进程无法用kill命令删除只能通过回收父进程或者重启系统来清理2.偏移量起始地址 目标地址偏移量存在的必要性见3.请看下面代码#includestdio.h#includestddef.h// offsetof宏依赖的头文件// 定义测试结构体包含不同类型成员体现内存对齐typedefstruct{inta;// 偏移0字节int占4字节charb;// 偏移4字节内存对齐补3字节doublec;// 偏移8字节double占8字节longlongd;// 偏移16字节重点验证的成员}obj;intmain(){// 1. 定义并初始化结构体变量obj test_obj{10,x,3.14,10086};// 2. 计算成员d的偏移量size_toffset_doffsetof(obj,d);printf( 核心验证偏移量 起始地址 成员地址 \n);printf(成员d的偏移量%lu 字节\n,offset_d);// 3. 基础验证结构体真实地址 偏移量 成员d地址// 转为char*按字节偏移再转回long long*指向成员dlonglong*calc_d_addr(longlong*)((char*)test_objoffset_d);// 直接取成员d的地址longlong*real_d_addrtest_obj.d;// 打印地址并验证一致性printf(结构体起始地址%p\n,test_obj);printf(计算出的d地址%p\n,calc_d_addr);printf(直接取的d地址%p\n,real_d_addr);printf(地址是否一致%s\n\n,calc_d_addrreal_d_addr?✅ 一致:❌ 不一致);// 4. 补充验证(struct obj*)0 方式的偏移量计算printf( 补充验证0基地址的偏移量计算 \n);// 以0为结构体起始地址取成员d的地址等价于偏移量longlong*zero_base_d_addr((obj*)0)-d;printf(以0为起始地址的d地址%p\n,zero_base_d_addr);printf(偏移量是否等于0基地址的d地址%s\n\n,(unsignedlong)zero_base_d_addroffset_d?✅ 是:❌ 否);// 5. 额外验证地址取值正确性确保地址指向的是目标成员printf( 取值验证 \n);printf(计算地址取值%lld\n,*calc_d_addr);printf(直接取d的值%lld\n,test_obj.d);return0;}运行结果核心验证偏移量 起始地址成员地址成员d的偏移量16 字节 结构体起始地址0x7ffd35feafe0 计算出的d地址0x7ffd35feaff0 直接取的d地址0x7ffd35feaff0 地址是否一致✅ 一致补充验证0基地址的偏移量计算以0为起始地址的d地址0x10 偏移量是否等于0基地址的d地址✅ 是取值验证计算地址取值10086 直接取d的值100863.正式开始剖析操作系统内核里面的数据结构structtast_struct{//进程其他属性/* …………………… */structlist_headlink;structlist_headqueue_link;structlist_headhash;/* 其他结构……………… */};Linux内核0.11代码那么为什么操作系统要这么做 为什么要把内部数据结构设计成这样全局进程链表list_head link管「所有存活进程」支持遍历全量进程如 ps 命令调度队列链表queue_link只管「待调度的 R 态进程」供 CPU 调度器快速选进程。多 list_head 嵌入结构体进程可同时加入多个链表零侵入扩展container_of 反推结构体地址链表只存通用节点不丢业务数据链表增删改查 O (1)调度 / 遍历效率最优。另外 通过偏移量准确定位其他属性通过list_node节点内存地址成员偏移量反向计算出task_struct首地址进而访问其他属性这样实现的妙处在于 一个tast_struct 就可以既属于双链表又可以属于调度队列未来还可以属于任何结构进程状态1.R运行状态合并就绪和运行态。要么进程在cpu上执行命令要么在排队等待cpu分配时间片比如死循环程序会一直处于该状态用 ps 命令查看可能显示 R前台运行或 R后台运行。创建状态凡是在调度队列里的都属于创建状态,创建状态是运行状态的过渡。创建状态结合cpu运行状态补充——前台进程后台进程想这些状态后面带号的都表示是前台进程不带加号的都表示后台进程1.前台进程的概念能从键盘中读取数据的拥有键盘文件的——叫做前台进程结论无论前台程序还是后台程序都可以向显示器打印。在Linux中有且只有一个前台进程就是我们使用的键盘2.为什么要存在前台/后台进程前台进程读取数据后台进行运行程序 可以大大提高效率。2.阻塞状态2.1S可中断睡眠状态进程因为等待某种资源但是资源没有就绪。CPU就会让当前进程阻塞直到资源就绪。因为等待导致不被调度叫做阻塞。比如键盘输入、等待网络传输数据、在比如文本编辑器。系统中大多数进程平时就处于这个状态。使用kill命令可以唤醒或者终止这个进程代码实例 下面我们用scanf函数 等待键盘输入但是我们就是不输入1#includestdio.h2#includeunistd.h34intmain()5{6printf(PID:%d\n,getpid());7inta;8scanf(请输入数值:%d,a);9return0;10}这里的S就表明是一个阻塞状态的进程[rootVM-0-12-centos~]# ps-ajx|head-1ps-ajx|grep30367PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND31934303673036731934pts/130367S10010:00./proc.exe28635305613056028635pts/230560S00:00grep--colorauto3036731933319343193431934pts/130367Ss10010:00-bash最佳实践——实例——我们s/canf时候 进程会等待我们从键盘手动输入数据。此时为了防止这个进程一直占用内存。就把这个调度队列放到了其所对应的硬件进程中。 什么时候从键盘中读取到数据 再什么时候回来结论进程是否阻塞就看tast-struct被放在哪个队列中2.2D不可中断睡眠状态也叫磁盘睡眠态。进程同样处于睡眠态 大多数是在等在磁盘I/o等关键操作完成。核心特点是操作系统也无法杀死他kill -9命令也无法杀死 例如向磁盘写入重要数据时候可能就处于该状态。2.3T停止态进程收到SIGSTOP信号后会被暂停执行直到收到SIGCONT信号才会回复运行 比如终端执行kill -SIGSTOP 进程号 就可以让目标进入该状态然后用 kill -SIGCONT 进程号 可恢复停止让后台程序获取数据停止态存在的必要性当发生越权、非法操作的时候、操作系统并不希望杀死进程。就可以将其变为停止态2.4t跟踪停止态和 T 状态类似但专门用于调试场景。当进程被 gdb 等调试工具跟踪时遇到断点就会进入该状态。 此状态下进程不能用 SIGCONT 信号唤醒只能通过调试工具的操作如继续执行指令恢复运行。遇到断点就暂停——调试视角遇到断点就t——系统视角3.挂起状态当内存资源严重不足的时候就将阻塞等待的进程 与swap分区进行换入和换出这个过程叫做挂起分为阻塞挂起和运行挂起挂起的本质是用时间换空间结论swap分区一般不能太大最佳实践为内存/2或者内存。如果swap太大 那么就会过渡依赖swap分区导致系统速度大幅度降低。僵尸进程和孤儿进程1.僵尸状态和僵尸进程什么是僵尸状态在子进程需要退出的时候代码和数据已经销毁。但是tast_struct还需要维持一段时间。这个时候就需要父进程来读取。如果这个时候父进程没有读取 那么就可能造成内存泄漏 此时的状态就是僵尸状态1#includestdio.h2#includeunistd.h3#includesys/wait.h45intmain(){6// 1. 创建子进程7pid_tchild_pidfork();89if(child_pid-1){// fork失败10perror(fork error);11return1;12}1314if(child_pid0){// 子进程逻辑15printf(子进程(PID: %d)我要退出了变成僵尸进程\n,getpid());16// 子进程立即退出执行完这行就结束17return0;18}else{// 父进程逻辑19printf(父进程(PID: %d)我不回收子进程(PID: %d)让它变成僵尸\n,getpid(),child_pid);20// 父进程进入死循环不退出、不调用wait/waitpid回收子进程21while(1){22sleep(1);// 每秒休眠避免CPU占满方便查看状态23printf(父进程子进程还没被回收...\n);24}25// 注释如果想回收子进程取消下面一行注释即可消除僵尸态26// wait(NULL); // 回收子进程退出状态27}2829return0;30}父进程(PID:8262)我不回收子进程(PID:8263)让它变成僵尸 子进程(PID:8263)我要退出了变成僵尸进程 父进程子进程还没被回收... 父进程子进程还没被回收... 父进程子进程还没被回收...可以看到这里的状态已经变为Z 表示是一个前台僵尸进程PPIDPID PGID SID TTY TPGID STATUIDTIME COMMAND82628263826231541pts/08262Z10010:00[proc.exe]defunct316748298829731674pts/38297S00:00grep--colorauto8263避免僵尸进程的措施wait(NULL)回收子进程退出状态内存泄漏问题 如果malloc new 出空间 我们直到free delete等操作可以避免内存泄漏。 那么加入我们直接杀掉进程 还会造成内存泄露吗 结论是不会造成内存泄漏。结论一般情况下就算存在内存泄漏对我们的程序计算机影响也不是很大最害怕的是一个死循环 它们不退出。我们现在几乎所有的软件 都是死循环。它们也叫做常驻进程2.孤儿进程僵尸进程是 子进程退出 父进程不管孤儿进程是 父进程直接退出 子进程不退出这个时候没了父进程 子进程就需要一个新的父进程 被领养此时这个子进程就叫做孤儿进程为什么要被领养必须领养未来会退出保证系统回收避免内存泄漏。否则一直为僵尸i进程结论一个进程变成孤儿进程 默认会变成后台程序代码#includestdio.h#includeunistd.h#includesys/wait.hintmain(){// 1. 创建子进程pid_tchild_pidfork();if(child_pid-1){// fork失败处理perror(fork error);return1;}if(child_pid0){// 子进程逻辑printf(【子进程】PID: %d | 父进程PID: %d\n,getpid(),getppid());// 子进程休眠10秒足够父进程退出变成孤儿进程sleep(10);// 休眠后再次打印父进程PID此时已被PID1接管printf(【子进程】休眠后 → 父进程PID: %d已被init/systemd接管\n,getppid());// 子进程执行完退出return0;}else{// 父进程逻辑printf(【父进程】PID: %d | 创建的子进程PID: %d\n,getpid(),child_pid);printf(【父进程】我要退出了子进程即将变成孤儿进程\n);// 父进程主动退出不等待子进程让子进程失去父进程return0;}}运行结果【父进程】PID:10873|创建的子进程PID:10874【父进程】我要退出了子进程即将变成孤儿进程 【子进程】PID:10874|父进程PID:10873[ljyVM-0-12-centos12-18]$ 【子进程】休眠后 → 父进程PID:1已被init/systemd接管

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询