当前位置:   article > 正文

linux进程!!父子进程fork、vfork、退出、wait(&status)、waitpid、execl/lp/v/vp族函数、system(* commad)、popen(*cmd,“r/w“)_linux fork进程退出

linux fork进程退出

 通过getpid获取当前进程号

sys 

pid = 0;交换进程,起着进程调度、资源分配作用

pid = 1;init进程, 系统初始化 譬如界面,

exit():函数exit()“立即”终止调用进程、进程中任何开的文件都被关闭;、进程的任何子进程被进程继承,

wait(&status)等待退出状态、整体长退出用WEXITSTAYUS(status);

waitpid(pid,&status,WNOHANG);//子进程pid,状态值、不挂起WNOHANG

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. int main()
  5. {
  6. pid_t pid;
  7. pid_t pid2;
  8. pid_t retpid;
  9. pid = getpid(); //获取当前pid
  10. printf("befer pid:%d\n",pid);
  11. retpid = fork(); //把fork的pid返回给retpid 如果大于0 就是当前进程 等于0是子进程
  12. pid2 = getpid();
  13. printf("after pid:%d\n",pid2);
  14. if(pid == pid2){ //第一次的两个pid相等在父进程中,第二次不等在子进程中
  15. printf("this is father pid:%d,retpid:%d\n",getpid(),retpid);
  16. }
  17. else{
  18. printf("this is child pid:%d,retpid:%d\n",getpid(),retpid);
  19. }
  20. return 0;
  21. }

 存储空间分配

 

  1. #include <sys/types.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. int main()//创建进程不断输入 输入为1 产生一个子进程 父进程什么都不干 让子进程干活
  5. {
  6. int data;
  7. pid_t pid;
  8. while(1){
  9. printf("qing shu ru data\n");
  10. scanf("%d",&data);
  11. if(data == 1){
  12. pid = fork();
  13. if(pid > 0){ //父进程
  14. }
  15. else if(pid == 0){ //子进程不断打印
  16. while(1){
  17. printf("this is child pid:%d\n",getpid());
  18. sleep(2);
  19. }
  20. }
  21. }
  22. else{
  23. // printf("shu ru de bu shi 1\n");
  24. }
  25. }
  26. return 0;

 vfork使用方法,用exit退出、break退出会打乱cnt

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #incldue <stdio.h>
  4. int main() //vfork 会先执行子进程 且共用一块内存 会改变数据的值用exit退出 否则破坏cnt值
  5. {
  6. pid_t pid;
  7. int cnt = 0;
  8. pid = vfork();
  9. if(pid > 0){
  10. while(1){
  11. printf("this is the father pid:%d\n",getpid());
  12. sleep(2);
  13. printf("this is father cnt:%d\n",cnt);
  14. }
  15. }
  16. else if(pid == 0){ //先执行子进程
  17. while(1){
  18. printf("this is the child pid:%d\n",getpid());
  19. sleep(2);
  20. cnt++;
  21. printf("cnt=%d\n",cnt);
  22. if(cnt == 5){
  23. exit(-1); //退出子进程 去执行父进程
  24. }
  25. }
  26. }
  27. return 0;
  28. }

 10中  进程退出:正常、异常退出

正常退出:main中return、调用exit(0)-----标准c库 会对数据处理保存后再退出,

_exif/Exit数据直接退出、线程执行结束---进程结束退出、调用函数pthread_

异常退出:调用abrt、ctel+c、线程取消

进程退出 :使用同一段退出代码,该代码段--是关闭相应进程的 打开描述符。关闭后并释放内存

父进程通过子进程退出的返回状态判断是否正常退出、活做了多少用wait卡住状态 跟vfork有点类似

  1. //wait等待退出的用法 wait(&status),WEXITSTATUS(status)、exit(5)
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. int main()
  8. {
  9. pid_t pid;
  10. int cnt = 0;
  11. pid = fork(); //产生一个子进程 用wait等待
  12. int status = 10; //status的值和exit退出值相等时说明 子进程正常结束
  13. // pid_t wait(int *status);
  14. if(pid > 0){ //父进程等待 子进程结束wait取status地址等待
  15. int num = wait(&status); //wait(null)也等待 但是不关系子进程退出状态
  16. printf("wait num = %d\n",num); //wait返回值num是子进程的pid号
  17. printf("fther wait status = %d\n",WEXITSTATUS(status)); //判断status
  18. //exit是否相等
  19. while(1){
  20. printf("this is the father pid:%d\n",getpid());
  21. sleep(2);
  22. }
  23. }
  24. else if(pid == 0){
  25. while(1){
  26. printf("this is the child pid:%d\n",getpid());
  27. sleep(2);
  28. cnt++;
  29. printf("cnt=%d\n",cnt);
  30. if(cnt == 5){
  31. exit(5); //子进程 先执行结束退出 把5传递给wait的status
  32. }
  33. }
  34. }
  35. return 0;
  36. }

 僵尸进程:父进程不收集子进程退出状态 

孤儿进程:子进程还未结束 父进程先结束了

waitpid(pid,&status,WNOHANG);用法和孤儿进程

  1. //僵尸进程 和孤儿进程
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/wait.h>
  6. int main()
  7. {
  8. pid_t pid;
  9. pid = fork();
  10. int cnt = 0;
  11. int status = 10;
  12. // pid_t waitpid(pid_t pid, int *status, int options);
  13. if(pid > 0){ //子进程还没结束父进程就先结束了
  14. printf("this is father pid:%d\n",getpid());
  15. }
  16. else if(pid == 0){ //子进程
  17. while(1){ //子进程用getppid打印父进程 第二次之后为1 用init函数收集父进程状态
  18. //init收留 防止产生更多的孤儿进程
  19. printf("this is child pid:%d\nfathepid:%d\n",getpid(),getppid());
  20. cnt++;
  21. printf("cnt = %d\n",cnt);
  22. if(cnt == 5){
  23. exit(5);
  24. }
  25. sleep(2);
  26. }
  27. }
  28. return 0;
  29. }

exec族函数:

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);

  1. //exex族函数 调用成功直接运行族函数中的可执行文件,不反回,错误返回-1
  2. //exexl exexlp execvp
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. int main()
  6. {
  7. // int execl(const char *path, const char *arg, ...);//注意exexl四个参数
  8. if(execl("./echarg","echarg","aa",NULL) == -1){ //成功直接执行 调用的可执行文件
  9. printf("exec error!!\n"); //错误返回-1
  10. perror("why:");
  11. }
  12. printf("mei you diao yong chenggong\n");
  13. return 0;
  14. }
  15. int main()
  16. {
  17. // int execl(const char *path, const char *arg, ...);
  18. if(execl("/bin/ps","ps","-aux",NULL) == -1){ //exexl参数(路径、文件名、传参、
  19. // NULL结尾)
  20. printf("exec error!!\n");
  21. perror("why:");
  22. }
  23. printf("mei you diao yong chenggong\n");
  24. return 0;
  25. }
  26. int main()
  27. {
  28. // int execl(const char *path, const char *arg, ...);
  29. if(execlp("date","date",NULL,NULL) == -1){ //exexlp不用加路劲 PATH已近声明
  30. printf("exec error!!\n");
  31. perror("why:");
  32. }
  33. printf("mei you diao yong chenggong\n");
  34. return 0;
  35. }
  36. int main()
  37. {
  38. // int execvp(const char *file, char *const argv[]);
  39. char *argv[] = {"data",NULL,NULL};
  40. if(execvp("date",argv) == -1){ //execvp两个参数 封装
  41. printf("exec error!!\n");
  42. perror("why:");
  43. }
  44. printf("mei you diao yong chenggong\n");
  45. return 0;
  46. }



int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);

 
int execvpe(const char *file, char *const argv[],char *const envp[])
int execle(const char *path, const char *arg,..., char * const envp[]);

exec族函数函数的作用:

我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。

返回值:
  exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。
参数说明:
path:可执行文件的路径名字
arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录

main函数中fork打开子进程,在子进程中exrcl("./changeData","changeData","test.txt",NULL)

直接写到if里面不够灵活,因为我们只能把子进程的程序代码粘贴过来执行,这样必须知道源代码,太长了也不好控制,比如希望子进程执行ls -a,这样是不行的,因为ls的源代码没有这样ls放在子进程里面就实现不了,

此时就是用exec族函数,可以直接把一个编译好的可执行程序,直接加载运行

  1. //fork创建子进程 在子进程中用execl函数执行可执行文件
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. int main()
  10. {
  11. pid_t pid;
  12. int data;
  13. while(1){
  14. scanf("%d",&data);//不要加换行
  15. printf("please input!\n");
  16. if(data == 1){ //输入为1 创建子进程
  17. pid = fork();
  18. printf("password");
  19. if(pid > 0){
  20. wait(NULL);//只要有等待就不会成为僵尸进程
  21. }
  22. else if(pid == 0){ //在子进程中调用changeData函数 传过去txt文件修改
  23. execl("./changeData","changeData","config.txt",NULL);
  24. }
  25. }
  26. }
  27. return 0;
  28. }
  29. /*
  30. int main() //execl执行的changeData程序
  31. {
  32. int fd;
  33. char *readBuf;
  34. fd = open("./config.txt",O_RDWR|O_CREAT,0600);
  35. int size = lseek(fd,0,SEEK_END);
  36. lseek(fd,0,SEEK_SET);
  37. readBuf = (char *)malloc(sizeof(char)*size + 8);
  38. read(fd,readBuf,size);
  39. char *p = strstr(readBuf,"LENG=");
  40. if(p == NULL){
  41. printf("mei zhao dao !\n");
  42. }
  43. p = p+strlen("LENG=");
  44. *p = '5';
  45. p = p+sizeof(char);
  46. *p = '5';
  47. lseek(fd,0,SEEK_SET);
  48. write(fd,readBuf,strlen(readBuf));
  49. close(fd);
  50. }
  51. */

system函数使用方法

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. { //system和exex函数大致相同
  5. //成功返回进程pid 不能返回时返回127 失败返回-1
  6. if(system("ls -l") == -1){ //先执行system函数 结束后 返回继续执行其他
  7. printf("erro\n");
  8. perror("why:\n");
  9. }
  10. printf("da yin cheng gong\n");
  11. return 0;
  12. }

 popen函数用法

  1. //pipe exec system一般用于子进程中执行可以执行文件
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. int main()
  6. {
  7. //pipe是流(只能r/w) 返回文件类型 用fread把里面内容读出来 并打印
  8. // FILE *popen(const char *command, const char *type);
  9. FILE *fp;
  10. char str[1024] = {0}; //用于存放读取文件
  11. fp = popen("ps -aux|grep ./a.out","r"); //pipo可以获取输出结果 返回文件类型
  12. // size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
  13. int n_fread = fread(str,1,1024,fp); //流 用fread获取内容
  14. printf("n_read:%d str:%s\n",n_fread,str);//打印
  15. fclose(fp);
  16. return 0;
  17. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/210727
推荐阅读
相关标签
  

闽ICP备14008679号