4.7 Linux进程

1. 守护进程

#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/param.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<time.h>

void init_daemon()
{
    int pid;
    int i;
    pid=fork();
if(pid<0)
exit(1); else if (pid>0) exit(0); setsid(); pid=fork();
if(pid<0) exit(1); else if (pid>0) exit(0); for(i=0; i<NOFILE; i++) close(i); chdir("/tmp"); umask(0); return; } void main() //这是一个不断往文件里输入日期时间的程序 { FILE *fp; time_t t; printf("pid = %d\n", getpid()); init_daemon(); while(1) { sleep(6); fp=fopen("hello.log","a"); if(fp>=0) { time(&t); fprintf(fp,"current time is:%s\n",asctime(localtime(&t))); fclose(fp); } } return; }

 2. 父子进程/fork()函数

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
    pid_t childpid;
    int status;
    childpid = fork();
    if (-1 == childpid){
        perror("fork()");
        exit(EXIT_FAILURE);
    }
    else if(0 == childpid)
    {
        puts("In child process");
        sleep(10);
        printf("\tchild pid = %d\n", getpid());
        printf("\tchild ppid = %d\n", getppid());
        exit(EXIT_SUCCESS);
    }else{
        waitpid(childpid, &status, 0);
        puts("in parent");
        printf("\tparent pid = %d\n", getpid());
        printf("\tparent ppid = %d\n", getppid());
        printf("\tchild process exited with status %d \n", status);
    }
    exit(EXIT_SUCCESS);
}

wait()函数:

原型: pid_t wait(int *status) 

进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

waitpid()函数:

原型: pid_t waitpid(pid_t pid,int *status,int options)

从本质上讲,系统调用waitpid和wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式。

参数:

status: 同上

pid:从参数的名字pid和类型pid_t中就可以看出,这里需要的是一个进程ID。但当pid取不同的值时,在这里有不同的意义。     

pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。

pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。   

pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。

pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。   

options: options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用

————————————————
原文链接:https://www.cnblogs.com/LUO77/p/5804436.html

fork()函数:

用于从一个已经存在的进程内创建一个新的进程,新的进程称为“子进程”,相应地称创建子进程的进程为“父进程”。使用fork()函数得到的子进程是父进程的复制品,子进程完全复制了父进程的资源,包括进程上下文、代码区、数据区、堆区、栈区、内存信息、打开文件的文件描述符、信号处理函数、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等信息,而子进程与父进程的区别有进程号、资源使用情况和计时器等。由于复制父进程的资源需要大量的操作,十分浪费时间与系统资源,因此Linux内核采取了写时拷贝技术(copy on write)来提高效率。由于子进程几乎对父进程完全复制,因此父子进程会同时运行同一个程序。因此我们需要某种方式来区分父子进程。区分父子进程常见的方法为查看fork()函数的返回值或区分父子进程的PID。

第一次使用fork()函数的同学可能会有一个疑问:fork()函数怎么会得到两个返回值,而且两个返回值都使用变量pid存储,这样不会冲突么?在使用fork()函数创建子进程的时候,我们的头脑内始终要有一个概念:在调用fork()函数前是一个进程在执行这段代码,而调用fork()函数后就变成了两个进程在执行这段代码。两个进程所执行的代码完全相同,都会执行接下来的if-else判断语句块。当子进程从父进程内复制后,父进程与子进程内都有一个"pid"变量:在父进程中,fork()函数会将子进程的PID返回给父进程,即父进程的pid变量内存储的是一个大于0的整数;而在子进程中,fork()函数会返回0,即子进程的pid变量内存储的是0;如果创建进程出现错误,则会返回-1,不会创建子进程。fork()函数一般不会返回错误,若fork()函数返回错误,则可能是当前系统内进程已经达到上限,或者内存不足。注意:父子进程的运行先后顺序是完全随机的(取决于系统的调度),也就是说在使用fork()函数的默认情况下,无法控制父进程在子进程前进行还是子进程在父进程前进行。

————————————————
原文链接:https://blog.csdn.net/nan_lei/java/article/details/81636473

3. 僵尸进程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(){
   pid_t id = fork();
   if(id < 0){
      perror("fork");
      return 1;
   }
   else if(id > 0){
      printf("parent [%d] is sleeping\n",getpid());
      sleep(100);
   }
   else{
      printf("child [%d] is begining\n",getpid());
      sleep(2);
      exit(1);
   }
   return 0;
}

子进程先于父进程退出后, 子进程的PCB需要其父进程释放, 但父进程并没有释放子进程的PCB, 这样的进程称为僵尸进程, 僵尸进程实际上是一个已经死掉的进程.

在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。这个僵尸进程需要它的父进程来为它收尸,如果他的父进程没有处理这个僵尸进程的措施,那么它就一直保持僵尸状态. 如果这时父进程结束了,那么进程号为1的进程(例如init进程)自动会接手这个子进程,为它收尸,它还是能被清除的。

但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。如果有大量的僵尸进程驻在系统之中,必然消耗大量的系统资源。但是系统资源是有限的,因此当僵尸进程达到一定数目时,系统因缺乏资源而导致奔溃。在实际编程中,避免和防范僵尸进程的产生显得尤为重要。

4. 孤儿进程

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

int main()
{
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork error:");
        exit(1);
    }
    if (pid == 0)
    {
        printf("I am the child process.\n");
        printf("pid: %d\tppid:%d\n",getpid(),getppid());
        printf("I will sleep 50 seconds.\n");
        sleep(50);
        printf("pid: %d\tppid:%d\n",getpid(),getppid());
        printf("child process is exited.\n");
    }
    else
    {
        printf("I am father process.\n");
        sleep(10);
        printf("father process is exited.\n");
    }
    return 0;
}

在操作系统领域中,孤儿进程指的是在其父进程执行完成或被终止后仍继续运行的一类进程。这些孤儿进程将被进程号为1的进程(例如init进程)所收养,并由进程号为1的进程(例如init进程)对它们完成状态收集工作。

posted on 2022-04-07 22:35  Hiteration  阅读(54)  评论(0编辑  收藏  举报

导航