孤儿僵尸守护进程

孤儿僵尸守护进程

  • 1. 孤儿进程:
  • 2. 僵尸进程:
  • 3. 守护进程:==(重点)==

1. 孤儿进程:

父进程退出,还没退出的子进程就变成了孤儿进程

不要怕,还有爷爷进程init:
孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
省流:父先退出,但子还未退出

想想我们如何模仿一个孤儿进程? 答案是: kill 父进程!

杀死某个可执行文件全部的进程
killall 可执行文件名

干点这个进程号
kill -9 进程号

查看mp1.exe这个可执行文件有哪些进程正在执行
ps -ef | grep mp1.exe
可以用下面这个程序进行模拟
// 模拟孤儿进程
#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include 

#include 
#include 

typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);

int main(int argc, char **argv)
{
    start_worker_processes(4); // 4核cpu
                               // 管理子进程
    wait(NULL);
    // printf("parent is over!\n");
    // return 0;
}

void start_worker_processes(int n)
{
    int i = 0;
    for (i = n - 1; i >= 0; i--)
    {
        spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");
    }
}

pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{

    pid_t pid;
    pid = fork();

    switch (pid)
    {
    case -1:
        fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);
        return -1;
    case 0:
        proc(data);
        return 0;
    default:
        break;
    }
    printf("start %s %ld\n", name, (long int)pid);
    return pid;
}

static void worker_process_init(int worker)
{
    cpu_set_t cpu_affinity; // cup亲人
    // worker = 2;
    // 多核高并发处理  4core  0 - 0 core 1 - 1  2 -2 3 -3
    CPU_ZERO(&cpu_affinity);
    CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3
    // sched_setaffinity
    if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1)
    {
        fprintf(stderr, "sched_setaffinity() failed\n");
    }
}

void worker_process_cycle(void *data)
{
    int worker = (intptr_t)data;
    // 初始化
    worker_process_init(worker);

    // 干活
    for (;;)
    {
        sleep(10);
        printf("pid %ld ,doing ...\n", (long int)getpid());
    }
}

2. 僵尸进程:

一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
  省流:子先退出,父未调用wait或waitpid

  1. 怎么查看僵尸进程:
      利用命令ps,可以看到有标记为的进程就是僵尸进程。
    孤儿僵尸守护进程_第1张图片
  2. 怎样来清除僵尸进程:
    干掉父进程,子进程会有init来回收
eg:
// 模拟僵尸进程
#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include 

#include 
#include 

typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);

int main(int argc, char **argv)
{
    start_worker_processes(4); // 给虚拟机配置了2核
    // 管理子进程
    // wait(NULL);
    for (;;) // 父不退出,子退出时父不使用wait或waitpid进行回收=>僵尸进程
    {
        sleep(1);
    }

    return 0;
}

void start_worker_processes(int n)
{
    int i = 0;
    for (i = n - 1; i >= 0; i--)
    {
        spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");
    }
}

pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{

    pid_t pid;
    pid = fork();

    switch (pid)
    {
    case -1:
        fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);
        return -1;
    case 0:
        proc(data);
        return 0;
    default:
        break;
    }
    printf("start %s %ld\n", name, (long int)pid);
    return pid;
}

static void worker_process_init(int worker)
{
    cpu_set_t cpu_affinity; // cup亲人
    // worker = 2;
    // 多核高并发处理  4core  0 - 0 core 1 - 1  2 -2 3 -3
    CPU_ZERO(&cpu_affinity);
    CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3
    // sched_setaffinity
    if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1)
    {
        fprintf(stderr, "sched_setaffinity() failed\n");
    }
}

void worker_process_cycle(void *data)
{
    int worker = (intptr_t)data;
    // 初始化
    // worker_process_init(worker);
    exit(1); // 子进程退出
    // 干活
    /*for (;;)
    {
        sleep(10);
        printf("pid %ld ,doing ...\n", (long int)getpid());
    }*/
}

3. 守护进程:(重点)

不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务。守护进程脱离于终端,是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端所产生的终端信息所打断(比如关闭终端等)。

那如何成为一个守护进程呢? 步骤如下:

  1. 调用fork(),创建新进程,它会是将来的守护进程.
  2. 在父进程中调用exit,保证子进程不是进程组长
  3. 调用setsid()创建新的会话区
  4. 将当前目录改成根目录(如果把当前目录作为守护进程的目录,当前目录不能被卸载他作为守护进程的工作目录)
  5. 将标准输入,标准输出,标准错误重定向到/dev/null.
    我们来看这个代码:
//守护进程示例
#include 
#include 

//生成一个守护进程,以后要生成一个守护进程直接复制这个函数daemon(0,0)
int daemon(int nochdir, int noclose)//0 0
{
    int fd;

    switch (fork()) {
    case -1://错误
        return (-1);
    case 0://子进程
        break;
    default://父进程
        _exit(0);
    }

    if (setsid() == -1)
        return (-1);

    if (!nochdir)//!0 = 1
        (void)chdir("/");//将当前目录改成根目录

	//!0 = 1
    if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
        (void)dup2(fd, STDIN_FILENO);//将标准输入,标准输出,标准错误重定向到/dev/null.
        (void)dup2(fd, STDOUT_FILENO);
        (void)dup2(fd, STDERR_FILENO);
        if (fd > 2)
            (void)close (fd);//重定向之后就干掉fd
    }
    return (0);
}

eg:
// 模拟守护进程
#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include 

#include 
#include 

#include 
#include 

typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);

// 生成一个守护进程
int daemon(int nochdir, int noclose) // 0 0
{
    int fd;

    switch (fork())
    {
    case -1: // 错误
        return (-1);
    case 0: // 子进程
        break;
    default: // 父进程
        _exit(0);
    }

    if (setsid() == -1)
        return (-1);

    if (!nochdir)         //! 0 = 1
        (void)chdir("/"); // 将当前目录改成根目录

    //! 0 = 1
    if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1)
    {
        (void)dup2(fd, STDIN_FILENO); // 将标准输入,标准输出,标准错误重定向到/dev/null.
        (void)dup2(fd, STDOUT_FILENO);
        (void)dup2(fd, STDERR_FILENO);
        if (fd > 2)
            (void)close(fd); // 重定向之后就干掉fd
    }
    return (0);
}

int main(int argc, char **argv)
{
    start_worker_processes(4); // 4核cpu
                               // 管理子进程
    wait(NULL);
    // printf("parent is over!\n");
    // return 0;
}

void start_worker_processes(int n)
{
    int i = 0;
    for (i = n - 1; i >= 0; i--)
    {
        spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");
    }
}

pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{
    daemon(0, 0); // 成为守护进程//
    pid_t pid;
    pid = fork();

    switch (pid)
    {
    case -1:
        fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);
        return -1;
    case 0:
        proc(data);
        return 0;
    default:
        break;
    }
    printf("start %s %ld\n", name, (long int)pid);
    return pid;
}

static void worker_process_init(int worker)
{
    cpu_set_t cpu_affinity; // cup亲人
    // worker = 2;
    // 多核高并发处理  4core  0 - 0 core 1 - 1  2 -2 3 -3
    CPU_ZERO(&cpu_affinity);
    CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3
    // sched_setaffinity
    if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1)
    {
        fprintf(stderr, "sched_setaffinity() failed\n");
    }
}

void worker_process_cycle(void *data)
{
    int worker = (intptr_t)data;
    // 初始化
    worker_process_init(worker);

    // 干活
    for (;;)
    {
        sleep(10);
        printf("pid %ld ,doing ...\n", (long int)getpid());
    }
}

wxncom@wxncom-virtual-machine:~/shared_bike/demo/fork_demo$ gcc multip_process_3.c -o mp3.exe
wxncom@wxncom-virtual-machine:~/shared_bike/demo/fork_demo$ ./mp3.exe
wxncom@wxncom-virtual-machine:~/shared_bike/demo/fork_demo$ ps -ef | grep mp3.exe
wxncom     3023      1  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3025      1  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3027      1  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3028      1  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3029   3028  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3034   1646  0 17:23 pts/1    00:00:00 grep --color=auto mp3.exe

你可能感兴趣的:(Linux,linux,c++,c)