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

做淘宝客网站 首选霍常亮泰安集团网站建设地点

做淘宝客网站 首选霍常亮,泰安集团网站建设地点,设计模板免费,c 在网站开发方面有优势吗fork函数#xff1a; 一个进程#xff0c;包括代码、数据和分配给进程的资源。fork#xff08;#xff09;函数通过系统调用创建一个与原来进程几乎完全相同的进程#xff0c;也就是两个进程可以做完全相同的事#xff0c;但如果初始参数或者传入的变量不同#xff0c;两…fork函数 一个进程包括代码、数据和分配给进程的资源。fork函数通过系统调用创建一个与原来进程几乎完全相同的进程也就是两个进程可以做完全相同的事但如果初始参数或者传入的变量不同两个进程也可以做不同的事。 一个进程调用fork函数后系统先给新的进程分配资源例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中只有少数值与原来的进程的值不同。相当于克隆了一个自己。 #include sys/types.h #include unistd.h pid_t fork(void);fork调用的一个奇妙之处就是它仅仅被调用一次 却能够返回两次它可能有三种不同的返回值 1在父进程中fork返回新创建子进程的进程ID 2在子进程中fork返回0 3如果出现错误fork返回一个负值 在fork函数执行完毕后如果创建新进程成功 则出现两个进程一个是子进程一个是父进程 在子进程中fork函数返回0在父进程中fork返回新创建子进程的进程ID 我们可以通过fork返回的值来判断当前进程是子进程还是父进程。fork出错可能有两种原因 1当前的进程数已经达到了系统规定的上限这时errno的值被设置为EAGAIN。 2系统内存不足这时errno的值被设置为ENOMEM。 创建新进程成功后系统中出现两个基本完全相同的进程这两个进程执行没有固定的先后顺序哪个进程先执行要看系统的进程调度策略。子父进程执行过程 #includestdio.h #include sys/types.h #include unistd.hint main() {pid_t pid;pid_t fpid;pidgetpid();printf(before fork:pid%d\n,getpid());fpidfork();printf(after fork:pid%d\n,getpid());if(pidgetpid()){printf(This is father printf,pid%d\n,pid);}else{printf(This son printf,pid:%d\n,getpid());}return 0; }运行结果 before fork:pid14396 after fork:pid14396 This is father printf,pid14396 after fork:pid14397 This son printf,pid:14397由结果可知在程序中父进程会把符合条件的整个代码 都执行一遍然后子进程开始执行fork()函数之后的 代码,子进程执行过程中不会执行fork()函数之前的 代码但是可以访问fork()函数之前父进程中的变量。 在语句fpidfork()之前只有一个进程在执行这段代 码但在这条语句之后就变成两个进程在执行了fork函数创建的新进程的存储空间是如何分配的 每一个进程都有自己的存储空间创建的新的进程也不例外在早期linux系统中会把父进程中的命令行参数、堆、栈、未初始化数据、初始化数据和正文全部拷贝一份到自己开辟的内存空间后来随着linux内核技术的更新并不是把所有的东西全部拷贝到自己的内存而是写时拷贝什么时候会写时才拷贝很显然当然是在共享同一块内存的类发生内容改变时才会发生。 写时拷贝技术 学习过fork我们都知道是父进程创建出一个子进程子进程作为父进程的副本 是父进程的拷贝。 可是每次fork出的子进程难道还要把父进程的各种数据拷贝一份有人会说不是父子进程不共享各种数据段吗如全局变量区 栈区 堆区 。如果不拷贝那不就成共享的吗其实有关子进程拷贝父进程的数据是这样的。如果子进程只是对父进程的数据进行读取操作那么子进程用的就是父进程的数据。如果子进程需要对某数据进行修改那么在修改前子进程才会拷贝出需要修改的这份数据对这份备份进行修改。这就满足了父子进程的数据相互独立互不影响的要求。这么做的初衷也是为了节省内存。 举个栗子如果一份代码中定义了10个数据。父进程执行的部分对这10个数据全部进行修改而子进程执行的部分只修改了一个数据子进程明明用不到其他9个数据那还何必让子进程拷贝全部数据多占用9个永远使用不到的数据内存 因此创建子进程只是将原父进程的pcb拷贝了一份。父子进程的pcb全部指向的是父进程原本就有的数据如果子进程里对数据进行了修改那么子进程的pcb里指向 被修改的数据的指针会指向一个自己新开辟的内存新开辟的内存里将父进程的数据拷贝过来然后再进行修改。这就是写时拷贝技术顾名思义只在写的时候才拷贝的技术。 关于参数的修改问题 #includestdio.h #include sys/types.h #include unistd.h int main() {pid_t pid;pid_t fpid;pidgetpid();int data10;printf(before fork:pid%d\n,getpid());fpidfork();printf(after fork:pid%d\n,getpid());if(pidgetpid()){printf(This is father printf,pid%d\n,pid);}else{printf(This son printf,pid:%d\n,getpid());datadata10;}printf(data%d\n,data);return 0; } 运行结果 before fork:pid14462 after fork:pid14462 This is father printf,pid14462 data10 after fork:pid14463 This son printf,pid:14463 data20//当数据发生改变时才会从父进程中将要改变的值拷贝一份到子进程自己开辟的内存中去。//不影响父进程中的值fork创建一个子进程的一般目的 .一个父进程希望复制自己,使父子进程同时执行不同的代码段在这个网络服务进程中是常见的。父进程等待客户端的服务请求。当这种请求到达时父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。一个进程要执行一个不同的程序这对shell常见的情况。在这种情况下子进程从fork返回后立即调用exec。 简单使用fork有bug后续完善 #includestdio.h #include sys/types.h #include unistd.h #include unistd.h int main() {pid_t pid;pid_t fpid1,fpid2;pidgetpid();int data10;while(1){printf(请输入数字:\n);scanf(%d,data);if(data1){fpid1fork();if(fpid10){printf(这是创建的第一个子进程\n);while(1){printf(-----------,pid%d\n,getpid());sleep(3);}}}else if(data2){fpid2fork();if(fpid20){printf(这是创建的第二个子进程\n);while(1){printf(-----------,pid%d\n,getpid());sleep(3);}}}}return 0; } vfork函数 #include sys/types.h #include unistd.h pid_t vfork(void); 功能vfork() 函数和 fork() 函数一样都是在已有的进程中创建一个新的进程但它们创建的子进程是有区别的。返回值成功子进程中返回 0父进程中返回子进程 ID。pid_t为无符号整型。失败返回 -1。fork() 与 vfock() 都是创建一个进程那它们有什么区别呢 fork() 父子进程的执行次序不确定。 vfork()保证子进程先运行,在它调用 exec进程替换 或 exit退出进程之后父进程才可能被调度运行。fork() 子进程拷贝父进程的地址空间子进程是父进程的一个复制品。 vfork()子进程共享父进程的地址空间准确来说在调用 exec进程替换 或 exit退出进程 之前与父进程数据是共享的 示例演示 #includestdio.h #include sys/types.h #include unistd.h #includestdlib.h int main() {pid_t pid;pid_t fpid;pidgetpid();int count0;fpidvfork();if(fpid0){while(1){printf(这是父进程,PID%d,count%d\n,pid,count);sleep(1);}}else if(fpid0){while(1){printf(这是子进程,PID%d\n,getpid());sleep(1);count;if(count3){exit(0);}}}return 0; } 以下是程序运行的结果 这是子进程,PID17935 这是子进程,PID17935 这是子进程,PID17935 这是父进程,PID17934,count3 这是父进程,PID17934,count3 这是父进程,PID17934,count3 由此可看出由vfork创建的子进程在退出前共享父进程地址空间 因为在子进程退出时父进程没有收集子进程的状态所以子进程变为僵尸进程。z表示僵尸进程s表示正在运行。 fhn 17999 0.0 0.0 0 0 pts/2 Z 21:03 0:00 [vfork] defunct 进程的退出方式 1正常退出 在main函数中执行return调用exit()函数调用_exit()或者_Exit()函数进程最后一个线程返回最后一个线程调用pthread_exit 2异常退出 调用about函数进程受到某个信号(如ctrlc)而该信号使程序终止 总结不管是那种退出方式最终都会执行内核中的同一段代码。这段代码用来关闭进程中所有打开的文件描述符释放它所占用的内存和其他资源。 退出方式比较 exit和return的区别exit是一个函数有参数而return是函数执行完后的返回。exit把控制权交给系统而return将控制权交给调用函数。exit和abort的区别exit是正常终止进程而about是异常终止。exit(int exit_cod):exit中的参数exit_code为0代表进程正常终止若为其他值表示程序执行过程中有错误发生比如溢出除数为0。exit()和_exit()的区别exit头文件stdlib.h中声明而_exit()声明在头文件unistd.h中。两个函数均能正常终止进程但是_exit()会执行后立即返回给内核而exit()要先执行一些清除操作然后将控制权交给内核。 父子进程终止的先后顺序不同会产生不同的结果。在子进程退出前父进程退出则系统会让init进程接管子进程。当子进程先于父进程终止而父进程又没有调用wait函数等待子进程结束子进程进入僵死状态并且会一直保持下去除非系统重启。子进程处于僵死状态是内核只保存该进程的一些必要信息以备父进程所需。此时子进程始终占用着资源同时也减少了系统可以创建的最大进程数。如果子进程先于父进程终止且父进程调用了wait或waitpid函数则父进程会等待子进程结束。 等待子进程退出 为什么要等待子进程退出因为创建子进程的目的就是为了执行别的代码然而子进程代码的执行情况我门不了解也不知道子进程是不是正常退出所以我们要等待子进程的退出收集子进程退出时返回的状态正常退出时根据退出码查看退出是代码的执行情况异常退出时查看异常退出的原因。如果父进程在子进程退出时没有收集子进程的退出状态则子进程就会变为僵尸进程创建子进程后子进程退出状态不被收集变成僵尸进程。爹不要它了除非爹死后变孤儿init进程养父接收。如果父进程是死循环那么该僵尸进程就变成游魂野鬼消耗空间。。 wait函数 进程一旦调用了wait就立即阻塞自己由wait自动分析是否当前进程的某个子进程已经退出如果让它找到了这样一个已经变成僵尸的子进程wait就会收集这个子进程的信息并把它彻底销毁后返回如果没有找到这样一个子进程wait就会一直阻塞在这里直到有一个出现为止。 #include sys/types.h #include sys/wait.h pid_t wait(int *wstatus); 参数status用来保存被收集进程退出时的一些状态 它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意 只想把这个僵尸进程消灭掉事实上绝大多数情况下我们都会这样想我们就可以设定这个参数为NULL。可使用wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的具体原因。宏函数可分为如下三组 1. WIFEXITED(status) 为非0 → 进程正常结束WEXITSTATUS(status) 如上宏为真使用此宏 → 获取进程退出状态 (exit的参数)2. WIFSIGNALED(status) 为非0 → 进程异常终止WTERMSIG(status) 如上宏为真使用此宏 → 取得使进程终止的那个信号的编号。3. WIFSTOPPED(status) 为非0 → 进程处于暂停状态WSTOPSIG(status) 如上宏为真使用此宏 → 取得使进程暂停的那个信号的编号。WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行//下面是使用方法注意status是指针 wpid wait(status) if(WIFEXITED(status)){ //正常退出printf(Im parent, The child process %d exit normally\n, wpid);printf(return value:%d\n, WEXITSTATUS(status));} 返回值 如果成功wait会返回被收集的子进程的进程ID 如果调用进程没有子进程调用就会失败此时wait返回-1同时errno被置为ECHILD。waitpid函数 pid_t waitpid(pid_t pid, int *wstatus, int options);从本质上讲系统调用waitpid和wait的作用是完全相同的但waitpid多出了两个可由用户控制的参数pid和options。 pid从参数的名字pid和类型pid_t中就可以看出这里需要的是一个进程ID但当pid取不同的值时在这里有不同的意义。pid0时只等待进程ID等于pid的子进程不管其它已经有多少子进程运行结束退出了只要指定的子进程还没有结束waitpid就会一直等下去。pid-1时等待任何一个子进程退出没有任何限制此时waitpid和wait的作用一模一样。pid0时等待同一个进程组中的任何子进程如果子进程已经加入了别的进程组waitpid不会对它做任何理睬。pid-1时等待一个指定进程组中的任何子进程这个进程组的ID等于pid的绝对值。 optionsoptions提供了一些额外的选项来控制waitpid目前在Linux中只支持WNOHANG和WUNTRACED两个选项这是两个常数可以用|运算符把它们连接起来使用比如 retwaitpid(-1,NULL,WNOHANG | WUNTRACED); 如果我们不想使用它们也可以把options设为0如retwaitpid(-1,NULL,0); 如果使用了WNOHANG不挂起参数调用waitpid即使没有子进程退出它也会立即返回不会像wait那样永远等下去就像当于在父进程执行的闲暇时间检查有没有退出的进程。虽然使用了这个收集到子进程退出的信息但是子进程还会变为僵尸进程。 而WUNTRACED参数由于涉及到一些跟踪调试方面的知识加之极少用到这里就不多费笔墨了有兴趣的读者可以自行查阅相关材料。 waitpid的返回值比wait稍微复杂一些一共有3种情况 当正常返回的时候waitpid返回收集到的子进程的进程ID如果设置了选项WNOHANG而调用中waitpid发现没有已退出的子进程可收集则返回0如果调用中出错则返回-1这时errno会被设置成相应的值以指示错误所在当pid所指示的子进程不存在或此进程存在但不是调用进程的子进程waitpid就会出错返回这时errno被设置为ECHILD
http://www.zqtcl.cn/news/617429/

相关文章:

  • 做网站还得备案大企业网站建设多少钱
  • 一般做网站空间大概多少钱电商网站开发公司
  • 海报模板在线制作免费网站如何建设个人网站
  • 网站集群建设的意义如何优化推广网站
  • 怎么给公司做免费网站服装品牌网页设计图片
  • 中国通信建设协会网站新手建网站教程
  • 做网站页面的需要哪些技巧wordpress 网址导航
  • 如何做美食网站设计广州网页设计招聘
  • 中国商标网商标查询官方网站页面模板怎么添加文章
  • 建设基础化学网站的经验如何建设网站pdf下载
  • 外贸公司网站设计公司做网站能挣钱不
  • 免费网站ppt模板下载济南建设网站公司
  • 网站建设技术托管免费空间域名注册免备案
  • 威海住房建设部官方网站专科网站开发就业方向
  • 做外贸网站多少钱成都网页设计专业
  • 北京比较好的网站公司在线医生免费咨询
  • 免费的个人网站怎么做企业网站管理系统软件
  • 枣庄住房和城乡建设局网站如何注册国外域名
  • 满洲里建设局网站网页设计公司的目标客户有哪些
  • 英文书 影印版 网站开发怀化组织部网站
  • 网站建设领域的基本五大策略要学会网站细节
  • dede做英文网站优化cms建站系统哪个好
  • eclipse sdk做网站邯郸技术服务类
  • 汕头网站网站建设西安网约车租车公司哪家好
  • 网站空间域名维护协议网络推广软件平台
  • 昆明网站建设公司猎狐科技怎么样wordpress主题打不开
  • 网站推广入口服饰网站建设 e-idea
  • 长沙网站建设电话2个女人做暧暧网站
  • 手机手机端网站建设电子商务网站建设步骤一般为
  • 上海金瑞建设集团网站怎样登陆网站后台