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

网站开发工程师考试百度云服务器wordpress

网站开发工程师考试,百度云服务器wordpress,新乡网站建设设计,教育局网站建设方案进程创建 初始fork函数 fork函数是为了创建子进程而生的#xff0c;通过fork函数之后#xff0c;我们的父进程的代码和数据是共享的#xff0c;我们这里是可以通过man手册进行查询的#xff0c;查询之后是可以发现fork函数是会返回两个值的至于为什么会返回两个值#x… 进程创建 初始fork函数 fork函数是为了创建子进程而生的通过fork函数之后我们的父进程的代码和数据是共享的我们这里是可以通过man手册进行查询的查询之后是可以发现fork函数是会返回两个值的至于为什么会返回两个值我们下面来进行探讨。 首先在我们之前的文章里讲过fork函数是会进行返回两个值的这个值相当于给父进程进行写入的。而且我们如果通过打印的化不难发现父进程返回的值就是我们创建出来子进程的pid而我们的子进程在fork函数之后返回的其实是0我们之前解释过为什么fork函数之后是会返回两个值的。 解释原因进程其实本质上就是内核的某种数据结构地址空间mm_struct 页表 PCBLinux下是task_struct 进程的代码和数据组成的然后在我们父进程如果进行创建子进程的过程中子进程的代码和数据其实就是继承父进程的代码和部分数据这里我们需要注意的是子进程的代码和父进程的代码是共享的但是我们子进程的数据和父进程的数据其实是独立的这就造成我们的返回值就可能是两个还有一个原因就是我们的数据大部分其实都是拷贝父进程的数据但是有些数据会进行写实拷贝啥是写时拷贝我后面再讲。 这样就确保我们每个进程都是独立的也就导致最后我们的返回值是两个 所以fork函数之后我们的操作系统其实上做了四点 分配新的内存块和内核数据结构给子进程 将父进程部分数据结构内容拷贝至子进程 添加子进程到系统进程列表当中 fork 返回开始调度器调度 fork函数返回值的意义 子进程返回的就是0 父进程返回的就是子进程的pid fork函数的常规用法 我们知道fork函数是为了创建子进程的那就证明子进程肯定是为了给父进程分担一些任务的比如父进程一写任务就会分给子进程还有的时候子进程会会自己单独执行一个程序 fork函数失败 fork函数有的时候创建进程的时候也是会失败的比如当我们的进程队列过多的时候fork函数就是会失效这和我们以前文章里不断进行malloc开空间是一样的道理我们在堆上开空间的时候本质就是给我们的程序创造空间程序最后实际上就是一个一个的进程所以fork函数也是会失败的。 所以fork 之后创建一批结构代码以共享的方式数据以写时拷贝的方式两个进程必须保证 独立性做到互不影响。在这种共享机制下子进程或父进程任何一方挂掉不会影响另一个进程。 写时拷贝 写时拷贝能让我们的进程具有独立性其中最大的特点应该是发生在数据上的不同。 为了让大家更好的理解写时拷贝我们先引出话题我们为什么要进行写时拷贝。 解释fork之后我们可以认为我们子进程是继承父进程的代码和数据但是我们知道我们的进程是具有独立性的看视两个相互矛盾的话题这就引出了我们为什么要进行写时拷贝的原因了我们如果为了确保独立性的化为什么不直接拷贝一份数据给子进程父子进程的代码和数据都拷贝一份自己的不就行了 但是这就是会造成空间的浪费我们子进程的大部分数据都是可以用父进程的所以如果拷贝一份确实会浪费空间我们这里也可以给出一个结论就是我们父子进程进行继承的时候子进程是会拷贝一份父进程的“东西的”,他们分别就是task_struct mm_struct(地址空间) 页表 代码和数据。 所以就能很好的减少成本提高我们操作系统的效率了。 总结 有浪费空间之嫌父进程的数据子进程不一定全用即便使用也不一定全部写入。最理想的情况只有会被父子修改的数据进行分离拷贝。不需要修改的数据共享即可。但是从技术角度实现复杂。如果 fork 的时候单独生成一份子进程会增加 fork 的成本内存和时间 所以这就是我们为什么要进行写时拷贝的原因我们下面可以通过一些图片来了解写时拷贝到底是什么 了解写时拷贝的过程 我们写时拷贝的时候通过这个图就可以看到虚拟地址是不变的但是通过页表进行映射的时候在内存种指向的空间就会发生拷贝我们可以认为新开出来的内存就是发生了写时拷贝的这样一个过程。 这里的写时拷贝的时候还是会发生一个小细节的我们不要以为创建子进程之后马上就是会发生写时拷贝的其实不是的我们只会在我们要用这个的时候才会进行使用我们可以认为操作系统对我们这个过程是有延时的因为我们可能不是马上就用这个空间只是开了出来这和我们C语言学的是一样的比如就是我们的malloc函数我们使用的时候是不是先开出来空间然后才是进行的使用而不是开出来就马上进行使用对吧 进程的终止 我们是可以给我们的进程分成三种情况的 第一种 代码正常运行 代码跑完结果也是正确的 第二种代码运行代码跑完之后但是结果是不正确的 第三种就是异常如果在我们语言方面是可以讲成程序崩溃 下面有个问题我们为什么要进行进程终止进程终止究竟是在干嘛 在这之前我们还要讲一个东西我们都知道我们如果写一个代码的化然后进行预处理编译汇编链接这四步之后我们会产生我们的可执行的程序我们可执行程序如果要运行就会形成进程进程其实本质上就是内核的某种数据结构地址空间mm_struct 页表 PCBLinux下是task_struct 进程的代码和数据组成的这我们上面是讲过的但是这里我们还是需要想想我们是先将我们的代码和数据放在内存里还是先创建task_struct和地址空间和页表呢 我们可以这么想在我们上大学的时候我们填完志愿之后学校录取你之后是你马上就要去学校吗我们肯定是会在要开学的时候才是会去学校的这个时候我们的信息是不是已经在学校里了但是我们人还是不需要去学校的所以我们的进程就是先创建PCB和地址空间还有我们的页表。然后才是我们程序的代码和数据。 那话又说回来进程终止到底是在干嘛呢答案就是先释放我们的代码和数据然后就是我们进程的内核的数据结构释放的顺序大家一定要记住的我们后面就会讲退出码和信号的时候就会用到。 我们先来写一下世界上最简单的代码。 这么简单的代码我肯定是故意打错的。 我们来改一下我们的代码吧. [tjlhecs-67680 3_22]$ make gcc -o myprocess myprocess.c [tjlhecs-67680 3_22]$ ./myprocess hello word [tjlhecs-67680 3_22]$ 看完操作之后来看看我们的代码 #include stdio.h int main() {printf(hello word\n);return 0; }接下来我们需要思考的就是我们为什么每次代码都需要return 0 为什么不是return 100 这些难道它这个返回值也是有不同的意义的。 进程的退出码 我们在我们主函数程序结束的时候会返回一个值这个值就是我们的退出码。 退出码是很重要的它主要就是给我们的父进程bash来看的这也就有有了我们上面进程终止的三种情况。 第一种 代码正常运行 代码跑完结果也是正确的 第二种代码运行代码跑完之后但是结果是不正确的 第三种就是异常如果在我们语言方面是可以讲成程序崩溃 echo $? 我们用这个指令就是可以查询我们的退出码了。 我们之前说过ls这些简单的指令也是一个进程我们也可以查出他们的退出码。 [tjlhecs-67680 3_22]$ ls adafa ls: cannot access adafa: No such file or directory [tjlhecs-67680 3_22]$ echo $? 2 [tjlhecs-67680 3_22]$ 当我们输入一个不认识的指令它也是会进行返回一个值的所以这个值是有它自己的意思我们可以来写一个代码来查看这些退出码的信息这个时候我们需要认识一个函数。 那我们来写一个循环的代码来进行查询。 0 :Success 1 :Operation not permitted 2 :No such file or directory 3 :No such process 4 :Interrupted system call 5 :Input/output error 6 :No such device or address 7 :Argument list too long 8 :Exec format error 9 :Bad file descriptor 10 :No child processes 11 :Resource temporarily unavailable 12 :Cannot allocate memory 13 :Permission denied 14 :Bad address 15 :Block device required 16 :Device or resource busy 17 :File exists 18 :Invalid cross-device link 19 :No such device 20 :Not a directory 21 :Is a directory 22 :Invalid argument 23 :Too many open files in system 24 :Too many open files 25 :Inappropriate ioctl for device 26 :Text file busy 27 :File too large 28 :No space left on device 29 :Illegal seek 30 :Read-only file system 31 :Too many links 32 :Broken pipe 33 :Numerical argument out of domain 34 :Numerical result out of range 35 :Resource deadlock avoided 36 :File name too long 37 :No locks available 38 :Function not implemented 39 :Directory not empty 40 :Too many levels of symbolic links 41 :Unknown error 41 42 :No message of desired type 43 :Identifier removed 44 :Channel number out of range 45 :Level 2 not synchronized 46 :Level 3 halted 47 :Level 3 reset 48 :Link number out of range 49 :Protocol driver not attached 50 :No CSI structure available 51 :Level 2 halted 52 :Invalid exchange 53 :Invalid request descriptor 54 :Exchange full 55 :No anode 56 :Invalid request code 57 :Invalid slot 58 :Unknown error 58 59 :Bad font file format 60 :Device not a stream 61 :No data available 62 :Timer expired 63 :Out of streams resources 64 :Machine is not on the network 65 :Package not installed 66 :Object is remote 67 :Link has been severed 68 :Advertise error 69 :Srmount error 70 :Communication error on send 71 :Protocol error 72 :Multihop attempted 73 :RFS specific error 74 :Bad message 75 :Value too large for defined data type 76 :Name not unique on network 77 :File descriptor in bad state 78 :Remote address changed 79 :Can not access a needed shared library 80 :Accessing a corrupted shared library 81 :.lib section in a.out corrupted 82 :Attempting to link in too many shared libraries 83 :Cannot exec a shared library directly 84 :Invalid or incomplete multibyte or wide character 85 :Interrupted system call should be restarted 86 :Streams pipe error 87 :Too many users 88 :Socket operation on non-socket 89 :Destination address required 90 :Message too long 91 :Protocol wrong type for socket 92 :Protocol not available 93 :Protocol not supported 94 :Socket type not supported 95 :Operation not supported 96 :Protocol family not supported 97 :Address family not supported by protocol 98 :Address already in use 99 :Cannot assign requested address 100 :Network is down 101 :Network is unreachable 102 :Network dropped connection on reset 103 :Software caused connection abort 104 :Connection reset by peer 105 :No buffer space available 106 :Transport endpoint is already connected 107 :Transport endpoint is not connected 108 :Cannot send after transport endpoint shutdown 109 :Too many references: cannot splice 110 :Connection timed out 111 :Connection refused 112 :Host is down 113 :No route to host 114 :Operation already in progress 115 :Operation now in progress 116 :Stale file handle 117 :Structure needs cleaning 118 :Not a XENIX named type file 119 :No XENIX semaphores available 120 :Is a named type file 121 :Remote I/O error 122 :Disk quota exceeded 123 :No medium found 124 :Wrong medium type 125 :Operation canceled 126 :Required key not available 127 :Key has expired 128 :Key has been revoked 129 :Key was rejected by service 130 :Owner died 131 :State not recoverable 132 :Operation not possible due to RF-kill 133 :Memory page has hardware error 134 :Unknown error 134 135 :Unknown error 135 136 :Unknown error 136 137 :Unknown error 137 138 :Unknown error 138 139 :Unknown error 139这些都是我们的退出码代表的我们来看看我们的代码是怎么写的。 #include stdio.h #include string.h int main() { // printf(hello word\n); // return 0;int i 0;for(i 0; i 255; i){printf(%d :%s\n,i,strerror(i));}return 0; }所以通过打印退出码所对应的信息我们是不难发现0就是代表成功的意思非0就是代表失败的意思从1 ——139都有对应的错误对应信息。这些信息就是来提示用户你这里是有问题的。所以这也就是为什么父进程bash需要获取子进程的退出码的原因了。 那我们今天还是需要来了解kill的一些选项也结合退出码更好的来判断信号。但是我们这里只是看效果并不是学信号信号的部分后面是会继续分享给大家的。 这个时候如果再来看我们的退出码就已经是没有用了因为这个时候不是合理退出我们的代码是没有跑完的我们代码写的内容其实就是一个死循环里面打印的就是当前进程的pid我们来看看我们的代码然后在进行解释。 这个时候我们称作为异常代码没有跑完我们的程序就已经进行退出的时候这个时候就称作为异常。 我们之前经常再语言层面对于异常来说的时候就是指我们的程序崩溃了但是现在在我们的操作系统的层面的时候我们其实就是可以认为进程被操作系统杀掉了。因为我们的进程做了不应该做的事然后被操作系统知道之后进行拦截了。 如果大家在牛客网上之前是写过代码的话有时候报错的时候就会显示段错误这个时候也就是我们的进程做了不该做的事情导致的段错误这个时候我们的退出码就是没有意义了。 退出码有的时候也不一定是操纵系统给我们安排的因为我们也可以使用自定义的退出码。 所以我们看我们进程退出的时候可以先来看我们的进程信号先检查是否是异常导致的然后再来看我们的退出码。 总结 衡量一个进程是否正确只需要来看它的退出信号和退出码就可以了。 再来分享一个知识点就是我们的子进程再退出的时候我们是先把它的代码和数据销毁然后在是内核数据的结构这个时候我们的子进程处于一种僵尸进程他是需要等待父进程来进行回收的所以就是会保留退出码和退出信号等着父进程来进行回收的。 如何终止我们的进程 我们可以用C语言的库函数来进行终止我们的程序。 exit函数 这就是我们exit函数中间的参数就是我们的退出码没错因为退出码是可以自定义的所以我们也能进行对我们的退出码进行修改。 exit表示进程的终止。直接退出。 下面来看看代码和具体效果。 那还是有一个函数就是_exit,其实他们两个没有什么不同唯一不同的就是_exit是系统接口。我们来继续写一个函数可以来对比一些下他们的不一样的地方。 这两个图其实就是可以说明了因为我们的代码没有加上\n所以是不会刷新缓冲区的但是等到代码结束的时候就是会强制刷新的然后_exit是没有进行刷新因为我们之前也是讲过我们的不能直接访问操作系统而是会通过系统接口进行访问的然后库函数exit其实还是会去调用_exit这个系统接口的,那么这里其实就是告诉大家我们的内存不是在系统中的在哪里后面继续讲。先埋下伏笔。 进程等待 我们上来就给出结论结论就是我们的父进程是会等待子进程的退出的 如果子进程退出的时候父进程不进行等待就会导致子进程一直处于僵尸进程我们知道僵尸进程是会一直存在的我们也不能用kill进行杀掉僵尸进程需要等待父进程来进行回收父进程回收的话需要收集子进程的退出信息。 那么我们为什么要进行进程等待呢如果不发生进程等待是会发生什么呢 父进程通过等待就可以解决子进程的信息会进行资源的回收一定要进行考虑的 获取子进程的退出信息退出信号和退出码不一定要进行考虑的 那我们这里需要来了解系统调用的函数分别是wait/waitpid我们先来看看wait但是我们主要还是看waitpid。先来写我们的代码。 可以看到我们的效果是这样的的确发现父进程就是在等待我们的子进程而且等待过程中子进程是处于僵尸进程。 #include stdio.h #include unistd.h #includestdlib.h #include sys/types.h #include string.h #include sys/wait.h void ChildRun() {int cnt 5;while(cnt){printf(I am child process, pid: %d, ppid:%d, cnt: %d\n, getpid(), getppid(), cnt);sleep(1);cnt--;} }int main() {printf(I am father, pid: %d, ppid:%d\n, getpid(), getppid());pid_t id fork();if(id 0){// childChildRun();printf(child quit ...\n);exit(123);}sleep(7);// fahterpid_t rid wait(NULL); // int status 0;// pid_t rid waitpid(id, status, 0);if(rid 0){printf(wait success, rid: %d\n, rid);}else{printf(wait failed !\n);}sleep(3);return 0; }所以这就是wait的用法这个就可以说明我们的父进程是会等待子进程的这里我们需要再进一步的解释一个问题就是父进程在等待子进程的过程中父进程是一直等待的只有等子进程结束之后那么父进程也就真正的结束掉了因为父进程是需要收集子进程的退出信息的。 下面我们就来解释一下waitpid是个怎么样子的。 我们可以来看看waitpid的参数 第一个其实是子进程的pid第二个就是我们的输出型的参数是和我们之前认识scanf函数是一样的。然后就是来看看使用。 #include stdio.h #include unistd.h #include string.h #include stdlib.h #include sys/types.h #include sys/wait.hvoid ChildRun() {int *p NULL;int cnt 5;while(1){printf(I am child process, pid: %d, ppid:%d, cnt: %d\n, getpid(), getppid(), cnt);sleep(1);cnt--;*p 100;} }int main() {printf(I am father, pid: %d, ppid:%d\n, getpid(), getppid());pid_t id fork();if(id 0){// childChildRun();printf(child quit ...\n);exit(123);}sleep(7);// fahter//pid_t rid wait(NULL);int status 0;pid_t rid waitpid(id, status, 0);if(rid 0){printf(wait success, rid: %d\n, rid);}else{printf(wait failed !\n);}sleep(3);printf(father quit, status: %d, child quit code : %d, child quit signal: %d\n, status, (status8)0xFF, status 0x7F); } wait 和 waitpid 都有一个 status 参数该参数是一个输出型参数由操作系统填充。 如果传递 NULL 表示不关心子进程的退出状态信息。 否则操作系统会根据该参数将子进程的退出信息反馈给父进程。 status 不能简单的当作整形来看待可以当作位图来看待具体细节如下图只研究 status 低 16 比特 位 那今天分享的内容就到这里我们下次再见
http://www.pierceye.com/news/716788/

相关文章:

  • 雄安专业网站建设方案长沙做网站建设
  • 微信上的网站实物黄金哪个网站做的好
  • 网站建设的作用和用途wordpress外网固定链接
  • 网站做多长时间才有流量上海商城网站制作公司
  • 做电影网站服务器网站如何备案 流程图
  • 太原建站模板搭建wordpress attachment
  • 购买腾讯备案网站网站错误列表
  • 怎么查看网站的外链php网站建设流程图
  • 顺企网萍乡网站建设wordpress 读者墙
  • 电力建设期刊网站投稿域名提供商
  • 广东网站备案需要多久oa信息化管理系统平台
  • 哪个网站可以做担保交易小程序排行榜
  • 网站用html做的怎么弄后台中铁十六局个人门户网
  • 一个网站怎么做流量统计佛山市seo广告优化工具
  • 机关网站建设需求文档国家住建部官网
  • 一条龙网站建设哪家好六安招聘网官网
  • 网站建设 中企动力阀门和建设银行类似的网站
  • 所有做运动的网站姜堰网网站
  • 广西汽车网网站建设影楼微网站建设方案
  • 企业展厅设计比较好的公司北京优化服务
  • 网站的icp 备案信息wordpress爆破字典
  • 福建厦门网站建设公司网站代码素材建设
  • 广州网络公司建站e语言可以做网站吗
  • 不想用原来的网站模板了就用小偷工具采集了一个可是怎么替换seo顾问张智伟
  • 效果好的徐州网站开发建设网站怎么学
  • 上海网站设计要多少钱建设银行个人网站打不开
  • 哪个网站做欧洲旅行比较好东营网站制作
  • 做pc端网站效果wordpress js 添加图片
  • 给装修公司做网站商标设计大全
  • 深圳做网站公司有哪些地方国际形势最新消息