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

济南专业做企业网站设计师主题 wordpress

济南专业做企业网站,设计师主题 wordpress,咸阳网站制作,wordpress主题目录位置Linux进程控制(2) #x1f4df;作者主页#xff1a;慢热的陕西人 #x1f334;专栏链接#xff1a;Linux #x1f4e3;欢迎各位大佬#x1f44d;点赞#x1f525;关注#x1f693;收藏#xff0c;#x1f349;留言 本博客主要内容讲解了进程等待收尾内容和进程的程序…Linux进程控制(2) 作者主页慢热的陕西人 专栏链接Linux 欢迎各位大佬点赞关注收藏留言 本博客主要内容讲解了进程等待收尾内容和进程的程序替换以及进程程序替换的原理进程程序替换的7个重要接口 文章目录 Linux进程控制(2)1.进程等待(续)2.进程程序替换2.1 程序替换是如何完成的---单线程版2.2程序替换的原理2.3引入多进程使用所有程序替换的接口熟悉所有的替换程序接口(7个) 1.进程等待(续) 我们稍微改造一下之前进程等待的时候父进程不要阻塞等待的代码让父进程真正的去运行一些任务。 我们采用函数回调的方式让父进程在等待子进程的时候也可以去运行自己的一些任务 #includestdio.h #includestring.h #includeunistd.h #includesys/types.h #includesys/wait.h #includestdlib.h#define TASK_NUM 10//预设一批任务 void sync_disk() {printf(这是一个刷新数据的任务\n); }void sync_log() {printf(这是一个同步日志的任务\n); }void net_send() {printf(这是一个网络发送的任务\n); } //保存相关的任务 typedef void (*func_t)(); //定义了一个函数指针类型 func_t orther_task[TASK_NUM] {NULL}; //装载任务 int Load_Task(func_t fuc) {int i 0;for(; i TASK_NUM; i){if(orther_task[i] NULL) break;}if(TASK_NUM i) return -1;else orther_task[i] fuc;return 0; }//初始化函数指针数组 void Init_Task() {for(int i 0; i TASK_NUM; i) orther_task[i] NULL;Load_Task(sync_disk); Load_Task(sync_log);Load_Task(net_send); }void Run_Task() {for(int i 0; i TASK_NUM; i){if(orther_task[i] NULL) continue;else orther_task[i]();} }int main() {pid_t id fork();if(id 0){//子进程int cnt 5;while(cnt){printf(我是子进程我还活着呢我还有%dS我的pid%d我的ppid%d\n, cnt--, getpid(), getppid());sleep(1);}exit(0);}Init_Task();while(1){int status 0;pid_t ret_id waitpid(id, status, WNOHANG);// 夯住了if(ret_id 0){printf(waitpid_error\n);}else if(ret_id 0){Run_Task(); sleep(1);continue;}else{printf(我是父进程我等待成功了我的pid%d我的ppid%d, ret_id: %d, child exit code: %d, child exit signal:%d\n,getpid(), getppid(), ret_id, (status 8)0xFF, status 0x7F);exit(0);}sleep(1); }return 0; } 运行结果 继续改进我们之前获取进程退出码的时候是使用(status 8) 0xFF的方式来进行获取的那么实际上C库也给我们提供了两个宏来帮助我们获取进程的退出码 status: WIFEXITED(status): 若为正常终止子进程返回的状态则为真。查看进程是否是正常退出 WEXITSTATUS(status): 若WIFEXITED非零提取子进程退出码。查看进程的退出码我们用这两个宏来优化一下我们等待成功也就是子进程结束的时候的代码 else { //等待成功 if(WIFEXITED(status)) { //正常退出 printf(wait success, child exit code :%d, WEXITSTATUS(status)); } else { //异常退出 printf(wait success, child exit signal :%d, status 0x7F); } exit(0); } 正常退出 异常退出我们尝试在父进程等待的时候杀掉子进程 2.进程程序替换 我们为什么需要创建子进程为了让子进程帮我执行特定的任务 ①让子进程执行父进程的一部分代码 ②如果子进程指向一段全新的代码呢这时候我们就需要进程的程序替换 也是为什么需要进程的程序替换。 2.1 程序替换是如何完成的—单线程版 代码 #includestdio.h #includestdlib.h #includeunistd.h int main() { printf(begin......\n); printf(begin......\n); printf(begin......\n); printf(begin......\n); printf(begin......\n); execl(/bin/ls, ls, -a, -l, NULL); printf(end........\n); printf(end........\n); printf(end........\n); printf(end........\n); printf(end........\n); return 0; } 运行结果 那么我们可以看到这个进程运行了开始的begin....,然后运行了ls,但是后面的end...却不见了。 这是因为发生了进程的程序的替换简要的原理就是操作系统通过提供的地址/bin/ls从磁盘中拿出ls然后选到指定的文件ls,在输入一些参数-a, -l以NULL表示结束。 2.2程序替换的原理 操作系统不动当前进程的内核数据结构而是去磁盘内部拿到要替换的数据和代码将我们当前进程的数据和代码替换掉。 当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。 所以进程的程序替换是没有创建新的进程的。 ①站在进程的角度 操作系统帮我们在磁盘内部找到我们要替换的数据和代码替换进程的数据和代码。 ②站在程序的角度 这个程序被加载了所以我们也称execl这类函数为加载器。 我们在回到一开始为什么我们程序后面的end.....却没有打印出来 原因是当我们加载程序替换的时候新的数据和代码就进入了进程当前进程后续没有没运行的代码就成为了老代码直接被替换了没有机会执行了。 所以进程的程序替换是整体替换而不是局部替换。 所以我们接下来引入多进程的程序替换 2.3引入多进程使用所有程序替换的接口 例程 #includestdio.h #includestdlib.h #includeunistd.h #includesys/types.h #includesys/wait.h int main() { pid_t id fork(); if(id 0) { //child printf(我是子进程%d, getpid()); execl(/bin/ls, ls, -a, -l, NULL); } sleep(2); //father waitpid(id, NULL, 0); printf(我是父进程%d\n, getpid()); return 0; }运行结果 我们看到execl之后父进程的内容也被运行了 因为进程的独立性所以进程的程序替换只会影响调用程序替换的子进程。 子进程加载新程序的时候是需要进行程序替换的发生写时拷贝(子进程执行的可是全新的代码啊新的代码所以代码区也可以发生写时拷贝) 那么对于execl这类加载函数它有没有返回值呢 答案是分情况 ①替换成功是没有返回值的 ②替换失败是有返回值的-1 原因是假设替换替换成功了那么我们该进程中的代码和数据都会被替换成新的代码和数据那么我们之前的返回值也就不复存在了并且我们也不需要返回值了。 替换失败的情况下进程之前的代码和数据还是存在的那么我们的返回值也是存在的从而可以返回。 所以我们调用了加载函数之后我们不用去判断它是否加载成功只需要在函数后面返回异常即可。 失败的例程 #includestdio.h #includestdlib.h #includeunistd.h #includesys/types.h #includesys/wait.h int main() { pid_t id fork(); if(id 0) { //child printf(我是子进程%d\n, getpid()); execl(/bin/lsss, lsss, -a, -l, NULL); exit(1); } sleep(2); //father int status; waitpid(id,status, 0); printf(我是父进程%d, child exit signal:%d\n, getpid(), WEXITSTATUS(status)); return 0; } 熟悉所有的替换程序接口(7个) ①int execl(const char *path, const char *arg, ...); 例如execl(/bin/ls, ls, -a, -l, NULL); l代表list path路径也就是告诉操作系统你要用来替换的程序在磁盘的哪个路径,例程里的/bin/ls arg文件是你要用来替换的文件名例程里面的ls。 其中的...是可变参数列表,例程中的那些参数-a , -l。 其中最后我们要特别的输入一个NULL参数,告诉函数参数结束了 ②int execv(const char *path, char *const argv[]); 相比较第一个函数的差别就是第一个函数要求我们一个一个的去传参数而第二个要求我们直接用数组的形式去传但是原则也是一样的数组的最后一个元素也要置成NULL。 我们在子进程内部调用的时候是这样的 先创建一个数组将这些参数一个一个放进去再传给execv即可 那么其实v就是vector就是数组的意思 char* const argv[] { ls, -a, -l, NULL }; // execl(/bin/lsss, lsss, -a, -l, NULL); execv(/bin/ls, argv); exit(1); } 运行结果 ③int execlp(const char *file, const char *arg, ...); p:当我们指定执行程序的时候只需要指定程序名即可系统会自动在**环境变量PATH**中查找。 也就是说我们要用于替换的程序必须在环境变量PATH中或者说我们在环境变量PATH中设置过 execlp(ls, ls, -a, -l, NULL); 那么其中的两个ls是不一样的一个是文件名一个是参数。 ④int execvp(const char *file, char *const argv[]); v:表示参数以数组的形式传入 p:表示在环境变量PATH中去寻找用于替换的文件 char* const argv[] { ls, -a, -l, NULL }; execvp(ls, argv); 运行结果 ⑤int execle(const char *path, const char *arg, ..., char * const envp[]); envp[]:叫做自定义环境变量当我们不想使用系统默认的环境变量的时候这个时候我们就传递一个envp 比如我们现在要让我们的调用exec目录下的ortherproc来替换myproc的子进程的后续代码 先用execl尝试一下 execl(./exec/ortherproc, ortherproc, NULL); 运行结果 换成的动态的效果再看看 下来我们尝试用execle来实现一下 proc.c char* const envp[] { MYENVPUCanCMe!, NULL }; execle(./exec/ortherproc, ortherproc,envp); ortherproc.cc for(int i 0; i 5; i) { cout 我是另一个程序我的PID是 getpid() endl; cout MYENVP: (getenv(MYENVP)NULL ? NULL : getenv(MYENVP)) endl; cout PATH: (getenv(PATH) NULL ? NULL : getenv(PATH)) endl; sleep(1); } 运行结果 我们看到自定环境变量打印出来了但是操作系统内部的环境变量却不见了所以我们可以得到一个结论 自定义环境变量覆盖了默认的环境变量 我们传默认的环境变量试试 extern char ** environ;execle(./exec/ortherproc, ortherproc,NULL , environ); 运行结果 那么如果我们两个都要呢那么有一个接口putenv给我们提供了一个将自定义环境变量追加到进程的默认环境变量的方法接下来我们尝试一下 putenv(MYENVPUCanCMe); execle(./exec/ortherproc, ortherproc, NULL, environ); 运行结果 插播一段 我们知道环境变量具有全局属性可以被子进程继承下去那么操作系统是怎么办到的 只需要用execle的最后一个参数传过去即可 那么我们是不是不需要putenv也能实现两个都能被子进程读取到呢 我们直接把自定义的环境变量export到bash中试试 [milavm-5wklnbmaja lesson6]$ export MYENVPUCanCMe [milavm-5wklnbmaja lesson6]$ echo $MYENVP UCanCMe运行结果 我们发现是可行的自定义环境变量----- bash -----父进程------子进程 ⑥int execvpe(const char *file, char *const argv[], char *const envp[]); p不需要指定路径只要在环境变量内部即可 v参数以数组的形式传入 e环境变量数组传入 使用方法都与上面的类似。 ⑦int execve(const char *filename, char *const argv[], char *const envp[]); 这个接口也不用过多介绍了使用方法都是一样的。 那么我们需要注意的是在linux的man手册中将区域六个接口都放在了3号手册唯独这个却放在了2号手册。 其实操作系统只给我们提供了一个程序替换的接口execve,剩下的几个接口都是由这个接口封装出来的。 并且我们程序替换的时候不仅可以替换C语言的甚至其他的语言都可以替换我上面的例子也做到了用C替换因为这些代码都是交给操作系统来处理的而不是编译器所以不论是什么语言都是可以替换的 到这本篇博客的内容就到此结束了。 如果觉得本篇博客内容对你有所帮助的话可以点赞收藏顺便关注一下 如果文章内容有错误欢迎在评论区指正
http://www.pierceye.com/news/846478/

相关文章:

  • 如何把网站转网站这几年做那些网站致富
  • 网站开发运维网页制作设计多少费用
  • 网站开发技术协议上海百度推广
  • 粤icp备网站建设 中企动力广州网站开发是什
  • 佛山+网站建设开发系统 平台
  • 运输房产网站建设健康南充app
  • 营销型网站推广公司最好的app开发公司
  • 做网站硬件江西省城乡建设陪训网官方网站
  • 深圳做小程序网站开发短视频剪辑在哪里学
  • 集约化网站建设广州网站制作
  • 如何做网站链接wordpress 视
  • 北京专业建设网站公司做网站那几步
  • 网站版式布局宁波百度推广优化
  • 邵阳专业网站设计网站建设打造营销型网站
  • 网站内部链接的策略成都装修公司网站建设
  • 网页制作与网站建设答案联合易网北京网站建设公司怎么样
  • 虚拟主机安装网站wordpress xss
  • 营销网站的优点网上服务大厅用户登录
  • 阿里云网站建设服务费会计科目网站域名改了帝国cms
  • 塑业东莞网站建设网站建设的课件
  • 制作网页网站教程网站开发一般用
  • 网站换空间 sitewordpress 下载功能
  • 国外优秀的字体设计网站西安地产网站制作公司
  • 微网站和普通网站区别租腾讯服务器做网站行吗
  • 西安网站品牌建设福州建设发展集团网站
  • 网站源码怎么有wordpress内嵌播放器
  • 南宁网站快速排名提升一起来做网站17
  • 网站做数据分析什么软件是做网站的
  • 邯郸移动网站建设建设网站的报价
  • 做网站优化期间能收到网站吗科技创新与应用