linux下的进程控制

进程的概念:

进程是一个程序一次执行的过程,它和程序有本质区别。程序是静态的,它是一些保存在磁盘上的指令的有序集合;而进程是一个动态的概念,它是一个运行着的程序,包含了进程的动态创建、调度和消亡的过程Linux的基本调度单位。

进程的标记:

OS会为每个进程分配一个唯一的整型ID,做为进程的标识号(pid)。进程除了自身的ID外,还有父进程ID(ppid),所有进程的祖先进程是同一个进程,它叫做init进程,ID1,init进程是内核自举后的一个启动的进程。init进程负责引导系统、启动守护(后台)进程并且运行必要的程序。

进程的pidppid可以分别通过函数getpid()和getppid()获得。

#include <stdio.h>
#include <stdlib.h> #include <unistd.h> 
int main()
{ 
       printf("pid:%d ppid:%d",getpid(),getppid())
       return 0;
}

进程的状态:

进程是程序的执行过程,根据它的生命周期可以划分成 3 种状态。

执行态:该进程正在运行,即进程正在占用 CPU。

就绪态:进程已经具备执行的一切条件,正在等待分配 CPU 的处理时间片。

等待态:进程不能使用 CPU,若等待事件发生(等待的资源分配到)则可将其唤醒。

进程的结构:

“数据段”放全局变量、常数以及动态数据分配的数据空间。

“代码段”存放的是程序代码的数据。

· “堆栈段”存放的是子程序的返回地址、子程序的参数以及程序的局部变量等

进程的创建:

Linux 下有四类创建子进程的函数:system(),fork(),exec*(),popen()

system()函数

system 函数通过调用 shell 程序/bin/sh –c 来执行 string 所指定的命令,该函数在内部是通过调用 execve(“/bin/sh”,..)函数来实现的。通过 system 创建子进程后,原进程和子进程各自运行,相互间关联较 少。如果 system 调用成功,将返回 0。

示例:

#include
#include 
int main()
{ 
  system("ls -l "); //system(“clear”);表示清屏 
  return 0;
}

此外,system函数后面的参数还可以是一个可执行程序,例如:
system(“/home/wangxiao/1”);如果想要执行system后面进程的时候,不至于对当前进程进 行阻塞,可以利用&将/home/wangxiao/1调到后台运行。
fork()函数
#include pid_t fork(void);
在 linux 中 fork 函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程, 而原进程为父进程。它和其他函数的区别在于:它执行一次返回两个值。其中父进程的返回值是子进程 的进程号,而子进程的返回值为 0.若出错则返回-1.因此可以通过返回值来判断是父进程还是子进程。
fork 函数创建子进程的过程为:使用 fork 函数得到的子进程是父进程的一个复制品,它从父进程继 承了进程的地址空间,包括进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进 程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端,而子进程所独有的只有它的进程 号、资源使用和计时器等。通过这种复制方式创建出子进程后,原有进程和子进程都从函数 fork 返回,
各自继续往下运行,但是原进程的 fork 返回值与子进程的 fork 返回值不同,在原进程中,fork 返回子进 程的 pid,而在子进程中,fork 返回 0,如果 fork 返回负值,表示创建子进程失败。
#include 
int main()
{ 
    printf("Parent process id:%d\n",getpid()); pid_t iRet = fork();
    if(iRet < 0){//出错 
     printf("Create child process fail!\n");
     }else if(iRet == 0){//表示子进程 
     printf("child process id:%d ppid:%d\n",getpid(),getppid());
     }else{//表示父进程 
      printf("parent process success,child id:%d\n",iRet);
     } 
     return 0;
}

//有人可能会有疑问:这里怎么if和else里面的语句都得到执行了,和我们以前的if…else结构相矛盾啊?此时相当于有两份main函数代码的拷贝,其中一份做的操作是if(iRet==0)的情况;
另外一份做的操作是else(父)的情况。所以可以输出2句话。提问:如何创建兄弟进程和爷孙进程?
进程的控制
用fork函数启动一个子进程时,子进程就有了它自己的生命并将独立运行。
如果父进程先于子进程退出,则子进程成为孤儿进程,此时将自动被 PID 为 1 的进程 (即 init)接管。孤儿进程退出后,它的清理工作有祖先进程 init 自动处理。但在 init 进程 清理子进程之前,它一直消耗系统的资源,所以要尽量避免。
Example1:写一个孤儿进程:
#include
#include
#include main()
{ 
   pid_t pid = fork(); if( pid == 0){
   while(1) ;
   } else {
   exit(10);
   }
}

通过ps–ef就可以看到此时子进程一直在运行,并且父进程是1号进程。
如果子进程先退出,系统不会自动清理掉子进程的环境,而必须由父进程调用 wait 或 waitpid 函数来完成清理工作,如果父进程不做清理工作,则已经退出的子进程将成为僵尸 进程(defunct),在系统中如果存在的僵尸(zombie)进程过多,将会影响系统的性能,所以 必须对僵尸进程进行处理。
进程的终止
进程的终止有 5 种方式: 
 main 函数的自然返回;
调用 exit 函数
调用_exit 函数
调用 abort 函数
接收到能导致进程终止的信号 ctrl+c SIGINT ctrl+\ SIGQUIT
前 3 种方式为正常的终止,后 2 种为非正常终止。但是无论哪种方式,进程终止时都将 执行相同的关闭打开的文件,释放占用的内存等资源。只是后两种终止会导致程序有些代 码不会正常的执行比如对象的析构、atexit 函数的执行等。
未完待续,欢迎关注


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值