再谈进程—从入门到出家

再谈进程—从入门到出家

首页模拟经营出家模拟器小游戏更新时间:2024-06-14

再谈进程—从入门到出家


这段时间由于工作上用到几个比较基础的进程编程,却发现自己好久没有接触进程了,都狂忘了!不得不感慨几句:老了老了~~~

趁着对进程的回忆,也总一个简单的总结,下次可以回头看看,也帮大家做一个回顾


这篇文章就叫——再谈进程—从入门到出家

创建进程

创建进程使用fork()函数,由fork函数创建的进程被称为子进程;

#include <unistd.h> pid_t fork(void);

注:fork函数被调用一次,但是返回两次,唯一的区别就是子进程的返回值是0,父进程的返回值则是新子进程的ID;

子进程是父进程的副本,子进程可以获得父进程的数据空间,堆和栈的副本,但是父子进程并不共享这些存储空间,父子进程共享这些正文段;

案例:

#include <sys/types.h> #include <unistd.h> int main() { pid_t pid; char* message; int n; pid = fork(); if(pid < 0) { perror("fork"); exit(1); } if(pid == 0) { message = "This is the child\n"; n = 6; } else { message = "This is the parent\n"; n = 3; } for(;n>0;n--) { printf(message); sleep(1); } return 0; }

看下结果:

root@iZuf67on1pthsuih96udyfZ:~/C /C _test/Progress# ./fork This is the parent This is the child This is the parent This is the child This is the parent This is the child This is the child root@iZuf67on1pthsuih96udyfZ:~/C /C _test/Progress# This is the child This is the child

父进程执行了三次,子进程执行了6次;


wait() 函数

首先,看一下wait() 函数的原型;

#include <wait.h> int wait(int *status)

函数功能:父进程一旦调用了wait就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止;

测试一

#include <sys/types.h> #include <sys/wait.h> #include <stdio.h> int main() { pid_t pid; pid = fork(); if(pid < 0) { perror("fork"); exit(-1); } if(pid == 0) { printf("This is the child,pid=%d\n",getpid()); //exit(5); } else { sleep(1); printf("This is the parent\n"); pid_t pt = wait(NULL); printf("out,%d\n",pt); } return 0; }

结果:

root@iZuf67on1pthsuih96udyfZ:~/C /C _test/Progress# ./fork1 This is the child,pid=20334 This is the parent out,20334

我们再次测试下,子进程一直不退出,看下父进程会不会结束:

测试二

代码:

#include <sys/types.h> #include <sys/wait.h> #include <stdio.h> int main() { pid_t pid; pid = fork(); if(pid < 0) { perror("fork"); exit(-1); } if(pid == 0) { while(1) { printf("This is the child,pid=%d\n",getpid()); sleep(3); } //exit(5); } else { sleep(1); printf("This is the parent\n"); pid_t pt = wait(NULL); printf("out,%d\n",pt); } return 0; }

结果:

root@iZuf67on1pthsuih96udyfZ:~/C /C _test/Progress# ./fork1 This is the child,pid=20344 This is the parent This is the child,pid=20344 This is the child,pid=20344 ^C

我们会发现wait函数起到了作用,一直阻塞等待子进程的结束,这样就不会产生僵尸进程;


进程还有很多知识,这个是最最基础的:

比如进程间通信:


信号

概念:

信号(signal)是linux进程通讯中唯一的异步通讯方式

信号从软件层次上看是对中断机制的一种模拟。一个进程收到信号时的处理方式与CPU收到中断请求时的处理方式一样。收到信号的进程会跳入信号处理函数,执行完后再跳回原来的位置继续执行

想必这个学过底层硬件的对这个很熟悉,比如单片机时钟中断等等,就是通过中断的方式去处理事件,然后返回;


信号处理方式:


首先看几个常用的信号


信号注册函数

函数原型:

#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);

第一个参数signum:指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。   第二个参数handler:描述了与信号关联的动作,它可以取SIG_IGN、SIG_DFL 、sighandler_t类型的函数指针

直接上案例:

信号案例一

#include <stdio.h> #include <signal.h> int main() { //SIG_IGN 忽略Ctrl c signal(SIGINT,SIG_IGN); while(1) { sleep(2); } return ; }

结果:

root@iZuf67on1pthsuih96udyfZ:~/C /C _test/signal# ./signal1 ^C ^C ^\Quit

这个使用了SIG_IGN表示忽略了SIGINT,也就是Ctrl C无效;

信号案例二

#include <stdio.h> #include <signal.h> int main() { //SIG_IGN ,启动默认的Ctrl c signal(SIGINT,SIG_DFL); while(1) { sleep(2); } return ; }

结果:

root@iZuf67on1pthsuih96udyfZ:~/C /C _test/signal# ./signal ^C

这里使用了信号SIG_DFL,表示了默认使用Ctrl C,一般我们会使用默认的,但是在一些特定情况下,我们会使用这个来恢复默认操作的;

信号案例三

#include <stdio.h> #include <signal.h> void fun(int signum) { printf("recv a signal,num is %d\n",signum); } int main() { signal(SIGINT,fun); while(1) { sleep(2); } return ; }

结果:

root@iZuf67on1pthsuih96udyfZ:~/C /C _test/signal# ./signal3 ^Crecv a signal,num is 2 ^Crecv a signal,num is 2 ^Crecv a signal,num is 2 ^Crecv a signal,num is 2 ^\Quit

这里其实改变了我们对信号SIGINT的使用,当我们使用CTRL C的时候,会执行我们自己定义的函数,但是同时,他的默认函数也会被我们函数所取代;

信号案例四

#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<signal.h> void alarm_fun(int signum) { printf("alarm out,signum = %d\n",signum); exit(1); } int main() { //定义信号 signal(SIGALRM,alarm_fun); //5s后会发送超时信号 alarm(5); int num = 0; scanf("%d",&num); //如果5s内输出,则清除闹钟 alarm(0); printf("num:%d\n",num); return 0; }

结果:

root@iZuf67on1pthsuih96udyfZ:~/C /C _test/signal# ./signal4 10 num:10 root@iZuf67on1pthsuih96udyfZ:~/C /C _test/signal# ./signal4 alarm out,signum = 14 root@iZuf67on1pthsuih96udyfZ:~/C /C _test/signal#

这段代码使用了SIGALRM信号,一般会搭配alarm函数一起使用,alarm函数会在时间到达后产生SIGALRM信号,当前进程捕获该信号,进入函数进行处理;如果我们这里将exit去掉,函数处理完成后,优惠再次回到当前进程中,继续等待输入,但是不会再次计时;


总结

这种想必大家一看就是太基础了,但是有时候长时间不去使用,也会产生遗忘,甚至不知道如何处理,基础回顾也是必须的!也许大家也可以在这篇基础的文章中,回顾和寻找到自己不足的地方进行改进;

往期精彩汇总


冰冻三尺,非一日之寒,水滴石穿,非一日之功,愿我们一起加油努力~

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved