以下是以前学习《unix环境高级编程》时的一些笔记和测试代码,好久没看过了,没有再次验证,存在错误的话,希望见谅,分享下主要是!!!
ps     查看系统中的进程   ps–axj
A与B在用户空间是不能通信的,相当于封闭的房子,也没有窗户,所以在用户空间是无法通信的
二:进程控制相关函数
1.fork()函数
功能:创建一个子进程
参数:没有参数
返回值:成功,返回二个值;0 --- 子进程中  >0(子进程的PID号) ---- 父进程中
出错,返回一个值-1
成功时,内核为何会返还二个值?
用户空间的进程,可以认为是一个封闭的房子(在用户空间),内核是怎样对用户空间这么多进程进行管理,怎样识别,是通过PID。
fork() 调用成功,内核则在用户空间创建一个进程(房子),这个房子和之前的进程代码段,数据段等都一样(除了PID之外)

以下两段fork函数简单的使用
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "stdlib.h"
int main()
{
pid_t pid;
pid=fork();
printf("hello linux\n");
usleep(200); //200微秒
printf("11111111111\n");
while(1);
return 0;
}
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "stdlib.h"
int main()
{
pid_t pid;
pid=fork();
if(pid >0)
{
printf("parent process run\n");
}
if(pid ==0)
{
printf("child process run\n");
}
while(1);
return 0;
}
getpid(); 获取本进程的PID号(返回值)
getppid();获取本进程父进程PID号(返回值)
exit():   进程退出函数
什么是僵尸进程?什么是孤儿进程?
  子进程退出,父进程没有退出,此时子进程处于Z(zobile)(僵尸) 状态,处于此状态的进程仍要耗费系统资源。子进程自己不能回收资源,只有父亲负责为子进程回收资源。父进程退出,子进程没有退出,此时子进程变为孤儿进程,会被1号进程收养,即init进程为其父进程。
例子1:
/*僵尸进程    查看进程pid状态等消息    可以终端使用命令ps aux或者ps axj*/
#include "signal.h"
#include "sys/types.h"
#include "stdio.h"
int main()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("创建进程失败\n");
return -1;
}
/*对于父进程首先是睡眠(8秒)S状态,8秒后进入R(运行)状态
对于子进程就变成了T状态;
*/
if(pid > 0)
{
sleep(8);//睡眠状态;
/*如果设置的waitpid设置为waitpid(pid,NULL,0)为阻塞,那么将不会产生僵尸进程,父进程会为其回收*/
if(waitpid(pid,NULL,WNOHANG) == 0)//等待子进程结束;可以设置为非阻塞(WNOHANG);
{
kill(pid,9);//杀死子进程,父进程没有结束,子进程将变成Z状态,因为父进程没有给子进程回收资源,子进程将变为僵尸进程;
}
while(1);
}
if(pid == 0)
{
printf("raise function before\n");
raise(SIGTSTP);//暂停程序,相当于ctrl+z; T状态
printf("raise function after\n");
exit(0);
}
}
如果我们要求:子进程退出,父进程没有退出,同时也不要子进程处于Z(zobile) 状态,而是完全结束,怎么办?
2.exit()--------库函数   进程的退出函数
头文件:#include “stdlib.h”
参数:  int 退出状态----- 假设:0 为正常退出,-1为非正常退出
exit中的参数退出状态主要作用是传递给父进程,父进程根据这些状态可判定子进程现在处于什么情况。父进程怎样接收到这个状态呢?是通过wait 或waitpid
exit()------系统调用函数----unistd.h
以下为exit()和_exit()基本使用

#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
int main()
{
printf("hello linux");
// fflush(stdout);
//_exit(0);
exit(0);
printf("1111111111111");
return 0;
}
3  wait()函数
所需头文件:
#include <sys/types.h>
          #include <sys/wait.h>
函数原型:
  pid_t wait(int *status)
函数参数:
 
status 是一个整型指针,指向的对象用来保存子进程退出时的状态。
                      status 若为空,表示忽略子进程退出时的状态
                      status 若不为空,表示保存子进程退出时的状态
另外,子进程的结束状态可由Linux中一些特定的宏来测定。
函数返回值:    成功:子进程的进程号  失败:-1
什么时候会阻塞,什么时候不会阻塞?
调用该函数使进程阻塞(睡眠),直到任一个子进程结束或者是该进程接收到了一个信号为止。
如果该进程没有子进程或者其子进程已经结束,wait函数会立即返回,即不会阻塞。
以下是关于wait函数的使用
#include "sys/wait.h"
#include "sys/types.h"
#include "stdio.h"
int main()
{
printf("wait before\n");
wait(NULL);
printf("wait after\n");
return 0;
}
#include "sys/types.h"
#include "stdio.h"
#include "unistd.h"
int main()
{
pid_t pid;
pid=fork();
if(pid <0 )
{
printf("creat process failure\n");
return -1;
} if(pid ==0)//child process
{
printf("this is child process\n") ;
while(1);
}
if(pid >0) //parent process
{
printf("this is parent process\n");
printf("parent process:wait before\n");
wait(NULL);
printf("parent process:wait after\n");
while(1);
}
return 0;
}

解析:

  子进程1: 
        printf     ------- pid
        sleep(10)  -------S                   10秒后   结束
        exit(1)
  子进程2: 
        printf     ------- pid
        sleep(20)  -------S                   S(睡眠状态)                    再过10秒   
        exit(3)
   父进程:
        printf---
        printf ---wait before
        pet=wait------------------S
        printf---wait after ret=%d               
        pet=wait                              S(睡眠状态)                         R(运行状态)
        printf  second wait ret=%d
#include "sys/types.h"
#include "sys/wait.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
pid_t pid;
int ret; pid = fork();
if(pid <0)
{
printf("creat process failure\n");
return -1;
} if(pid == 0) //child process1
{
printf("this is a child process,pid=%d\n",getpid());
sleep(10);
exit(1); }
if(pid >0)
{
pid_t pid1;
pid1=fork();
if(pid1<0)
{
printf("creat child process1 failure\n");
exit(2);
}
if(pid1 ==0)
{
printf("this is a child process1 run,pid=%d\n",getpid());
sleep(20);
exit(3);
} printf("this is a parent process\n");
printf("wait before\n");
ret=wait(NULL);
printf("wait after,first wait ret=%d\n",ret);
ret=wait(NULL);
printf("second wait after,ret=%d\n",ret);
while(1); return 0; }
4. waitpid()   功能比wait 功能更强
可以等待某一个子进程退出,可通过第一个参数来实现
所需头文件:#include <sys/types.h>
         #include <sys/wait.h>
函数原型: pid_t waitpid(pid_t pid, int *status, int options)
函数参数: pid    pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
          pid=-1:等待任何一个子进程退出,此时和wait作用一样。
          pid=0:等待其组ID等于调用进程的组ID的任一子进程。
          pid<-1:等待其组ID等于pid的绝对值的任一子进程。
          status   
同wait
          options   WNOHANG:若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0
         WUNTRACED:若某实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
          0:同wait,阻塞父进程,等待子进程退出。
函数返回值:   正常:结束的子进程的进程号
         使用选项WNOHANG且没有子进程结束时:0
         调用出错:-1
例子:
#include "sys/types.h"
#include "sys/wait.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
pid_t pid;
int ret;
int status; pid = fork();
if(pid <0)
{
printf("creat process failure\n");
return -1;
} if(pid == 0) //child process1
{
printf("this is a child process,pid=%d\n",getpid());
sleep(10);
exit(1); }
if(pid >0)
{
pid_t pid1;
pid1=fork();
if(pid1<0)
{
printf("creat child process1 failure\n");
exit(2);
}
if(pid1 ==0)
{
printf("this is a child process1 run,pid=%d\n",getpid());
sleep(20);
exit(3);
} printf("this is a parent process\n");
printf("wait before\n");
ret=waitpid(pid1,&status,0);
printf("wait after,first wait ret=%d,status=%d\n",ret,WEXITSTATUS(status));
// ret=wait(&status);
// printf("second wait after,ret=%d,status=%d\n",ret,WEXITSTATUS(status));
while(1);
return 0;
}
}
5  vfork()    ----形式和fork()
vfork() 调用成功,内核则在用户空间创建一个进程,但是不会重新建立一个房子,父子里程共享父进程这个房子,然后子进程先运行,父进程后运行
6.在此之前创建子进程,子进程进行了代码的完全拷贝,虽然我们用返回值的不同使得父子进程执行了二个不同的代码区。但是很多情况下:
      父子进程的代码完全不一样,比如 bash 这是父进程,a.out 是子进程,这二段代码没有相似性;或父进程是C代码,子进程是一个shell脚本,等,我们应该怎么处理?
       当进程认为自己不能再为系统和用户做出任何贡献了时就可以调用exec函数,让自己执行新的程序,我们应该怎么处理?
伪代码:
int main()                           computer 这个可执行程
{                                     
  printf(“dfdfggf\n”);
  i++;
  .....
  Computer//不是函数,而是另外一个程序
}
可以通过exec 函数族来解决这些问题。
函数的功能:可以调用另外一个程序来运行,会把原来的程序中的代码段,数据段等都替换掉,从这个调用的程序的开始来执行,会保留原进程的PID,其它都不保留。
什么时候要用这个函数呢?
      当进程认为自己不能再为系统和用户做出任何贡献了时就可以调用exec函数,让自己执行新的任务。
如果某个进程想同时执行另一个程序,它就可以调用fork函数创建子进程,然后在子进程中调用任何一个exec函数。这样看起来就好像通过执行应用程序而产生了一个新进程一样。

所需头文件:#include <unistd.h>
函数原型:   int execl(const char *path, const char *arg, ...);
                   int execv(const char *path, char *const argv[]);
                   int execle(const char *path, const char *arg, ..., char *const envp[]);
                   int execve(const char *path, char *const argv[], char *const envp[]:xp[]);
                   int execlp(const char *file, const char *arg, ...);
                   int execvp(const char *file, char *const argv[]);//环境变量加
函数返回值:    -1:出错,成功是0
参数:        第一个参数,前面四个都一样,后面二个一样,path  file
                   path 必须要指定所在程序的路径,要不是绝对路径或相对路径
                   file  不用指定路径(指定路径也可以),在环境变量PATH中找这个程序
char * 逐个列举
例如这样一个程序
ls  –l  /mnt   ./child/xxx          “./child/xxx”  NULL
怎样传递这个参数呢? 
“ls” “-l” “/mnt”  NULL   
采用字符指针数组的方式传递参数
char *argv[]={“ls” “-l” “/mnt”  NULL }

第一个参数:有二类,char *path—不仅要指定程序的名称也要指定程序的路径 
char *file----指定程序的名称,你这个程序的所在路径一定要在环境变量位PATH中找到
第二参数:  char *arg ……   char *argv[]
execl例子
#include "stdio.h"
#include "unistd.h"
int main()
{
printf("exec before\n");
execl("./xxx","./xxx",NULL);
printf("exec after\n");
return 0;
}

execv例子

#include "stdio.h"
#include "unistd.h"
int main()
{
char *buf[]={"./child/xxx",NULL};
printf("exec before\n");
execv("./child/xxx",buf);
printf("exec after\n");
return 0;
}

execvp例子

#include "stdio.h"
#include "unistd.h"
int main()
{
char *buf[]={"xxx",NULL};
printf("exec before\n");
execvp("xxx",buf);
printf("exec after\n");
return 0;
}

笔记二:进程间的通信(fork、孤儿进程,僵死进程等)的更多相关文章

  1. c 进程间的通信

    在上篇讲解了如何创建和调用进程 c 进程和系统调用 这篇文章就专门讲讲进程通信的问题 先来看一段下边的代码,这段代码的作用是根据关键字调用一个Python程序来检索RSS源,然后打开那个URL #in ...

  2. Python网络编程(进程池、进程间的通信)

    线程池的原理:        线程池是预先创建线程的一种技术.线程池在还没有任务到来之前,        创建一定数量的线程,放入空闲队列中.这些线程都是处于睡眠状态,        即均为启动,不消 ...

  3. Linux进程间的通信

    一.管道 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: A. 管道是半双工的,数据只能向一个方向流动: B. 需要双工通信时,需要建立起两个管道: C. 只能用于父子进程或者兄弟 ...

  4. [Socket]Socket进程间的通信

    转自:http://blog.csdn.net/giantpoplar/article/details/47657303 前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket ...

  5. c++ 网络编程(三) LINUX/windows 进程间的通信原理与实现代码 基于多进程的服务端实现

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9613027.html 锲子:进程与线程是什么,他们的区别在哪里: 1 进程概念 进程是程序的一 ...

  6. 进程间的通信—套接字(socket)

      前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程.通常我们使用socket进行网 ...

  7. python全栈开发day32-进程创建,进程同步,进程间的通信,进程池

    一.内容总结 1.进程创建 1) Process:两种创建一个新进程的方法: 1.实例化Process,通过args=(,)元组形式传参,2创建类继承Process,类初始化的时候传参数 2) p.j ...

  8. Android进程间的通信

    1.概述:由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于 ...

  9. Nginx学习——Nginx进程间的通信

    nginx进程间的通信 进程间消息传递 共享内存 共享内存还是Linux下提供的最主要的进程间通信方式,它通过mmap和shmget系统调用在内存中创建了一块连续的线性地址空间,而通过munmap或者 ...

  10. Python 35 进程间的通信(IPC机制)、生产者消费者模型

    一:进程间的通信(IPC):先进先出  管道:队列=管道+锁 from multiprocessing import Queue q=Queue(4) q.put(['first',],block=T ...

随机推荐

  1. 【内存管理】ION内存管理器(carveout heap预留内存)

    什么是carveout heap carveout heap从代码中给的解释来看,是reserved预留的物理内存来实现的,这些内存buddy系统是没办法看到和管理到的 carveout heap中的 ...

  2. 【随便翻翻】Steam Deck现在(基本上)不通过预订就能购买到

    根据Valve的消息,你不再需要通过预订来购买这家公司于今年早些时候发售的掌上游戏机Steam Deck.每个型号现在都应该可以购买到.在撰写本文时(2022年10月7日),Valve预计所有型号的交 ...

  3. 1022 Digital Library (30分)

    本题题意很好读,看上去也不难写 写完运行才发现输出title只有一个单词... 后来把cin >> t换成了getline(cin, t) 还有一个坑点: Line #1: the 7-d ...

  4. Java中简单易懂的HashMap面试题(面试必备)

    这篇文章仅限小编个人的理解,小编不是Java方向的,只是对Java有很高的学习兴趣 如果有什么不对的地方还望大佬指点 HashMap的底层是数组+链表,(很多人应该都知道了) JDK1.7的是数组+链 ...

  5. linux离线安装插件包

    1.下载插件包(联网的linux环境下) # 检查是否安装了vim(vim-minimal是vi) [root@localhost opt]# rpm -qa | grep vim vim-minim ...

  6. nginx配置权重,ip_hash....

    nginx为后端web服务器(apache,nginx,tomcat,weblogic)等做反向代理 几台后端web服务器需要考虑文件共享,数据库共享,session共享问题.文件共享可以使用nfs, ...

  7. Python学习笔记--高阶技巧

    闭包(避免全局变量被修改的风险) 函数的嵌套的利用 若是只是调用到外部函数的值,只需要用到函数的嵌套,具体实现如下: 若是要对外部函数的值进行修改,需要用到nonlocal关键字,具体实现如下: at ...

  8. Spring--注解开发定义Bean

    注解开发 先看一看之前的bean的做法: 所谓注解开发,当然就要用到注解啊,就是在BookDao接口的实现类里面进行注解的定义 如图所示: 而在.xml文件里面,就需要进行这样一个操作: 注解当然不会 ...

  9. Java8 Optional使用方式

    参考博客:https://blog.csdn.net/zjhred/article/details/84976734

  10. 开源不易、安全慎行,中国软件如何走向文明?丨RTE 技术环境月报 202205

    各位开发者小伙伴: 这里是 2022 年第 5 期的 RTE<技术环境月报>--致力于成为对大家"有用"的 Highlight 看板--每月初通过 RTC 开发者社区( ...