GVKun编程网logo

UNIX-Linux 环境编程(五):进程管理(linux进程管理命令使用)

4

如果您想了解UNIX-Linux环境编程和五:进程管理的知识,那么本篇文章将是您的不二之选。我们将深入剖析UNIX-Linux环境编程的各个方面,并为您解答五:进程管理的疑在这篇文章中,我们将为您介绍

如果您想了解UNIX-Linux 环境编程五:进程管理的知识,那么本篇文章将是您的不二之选。我们将深入剖析UNIX-Linux 环境编程的各个方面,并为您解答五:进程管理的疑在这篇文章中,我们将为您介绍UNIX-Linux 环境编程的相关知识,同时也会详细的解释五:进程管理的运用方法,并给出实际的案例分析,希望能帮助到您!

本文目录一览:

UNIX-Linux 环境编程(五):进程管理(linux进程管理命令使用)

UNIX-Linux 环境编程(五):进程管理(linux进程管理命令使用)

进程管理

  • 一、基本概念
        • 1. 进程与程序
        • 2. 进程的分类
        • 3. 查看进程
        • 4) 进程信息列表
  • 三、fork
  • 四、vfork
  • 五、进程的正常退出
  • 六、进程的异常终止
  • 七、wait/waitpid
  • 八、exec
  • 九、system

一、基本概念

1. 进程与程序

1) 进程就是运行中的程序。 

一个运行着的程序,可能有多个进程。进程在操作系统中执行特定的任务。
2) 程序是存储在磁盘上, 包含可执行机器指令数据的静态实体
进程或者任务是处于活动状态的计算机程序。

2. 进程的分类

1) 进程一般分为**交互进程****批处理进程****守护进程**三类。
2) 守护进程总是活跃的,一般是后台运行。 

守护进程一般是由系统在开机时通过脚本自动激活启动,
或者由超级用户 root 来启动。

3. 查看进程

1) 简单形式 

ps
以简略方式显示当前用户有控制终端的进程信息。

2) BSD风格常用选项 

ps axu
a - 所有用户有控制终端的进程
x - 包括无控制终端的进程
u - 以详尽方式显示
w - 以更大列宽显示



3) SVR4风格常用选项 

ps -efl
-e 或 - A - 所有用户的进程
-a - 当前终端的进程
-u 用户名或用户 ID - 特定用户的进程
-g 组名或组 ID - 特定组的进程
-f - 按完整格式显示
-F - 按更完整格式显示
-l - 按长格式显示






4) 进程信息列表

◦USER/UID: 进程属主。
◦PID: 进程ID。
◦%CPU/C: CPU使用率。
◦%MEM: 内存使用率。
◦VSZ: 占用虚拟内存大小(KB)。
◦RSS: 占用物理内存大小(KB)。
◦TTY: 终端次设备号,“?”表示无控制终端,如后台进程。
◦STAT/S: 进程状态。可取如下值: 
		◾O - 就绪。等待被调度。
		◾R - 运行。Linux下没有O状态,就绪状态也用R表示。
		◾S - 可唤醒睡眠。系统中断,获得资源,收到信号,都可被唤醒,转入运行状态。
		◾D - 不可唤醒睡眠。只能被wake_up系统调用唤醒。
		◾T - 暂停。收到SIGSTOP信号转入暂停状态, 收到SIGCONT信号转入运行状态。
		◾W - 等待内存分页(2.6内核以后被废弃)。
		◾X - 死亡。不可见。
		◾Z - 僵尸。已停止运行,但其父进程尚未获取其状态。
		◾< - 高优先级。
		◾N - 低优先级。
		◾L - 有被锁到内存中的分页。实时进程和定制IO。
		◾s - 会话首进程。
		◾l - 多线程化的进程。
			◾
				◾
					◾+ - 在前台进程组中。
◦PSR: 进程被绑定到哪个处理器。
  1. 父进程、子进程、孤儿进程和僵尸进程

    1. 父进程启动子进程后,子进程在操作系统的调度下与其父进程同时运行。
    2. 子进程先于父进程结束,子进程向父进程发送 SIGCHLD (17) 信号,父进程回收子进程的相关资源。
    3. 父进程先于子进程结束,子进程成为孤儿进程,同时被 init 进程收养,即成为 init 进程的子进程。
    4. 子进程先于父进程结束,但父进程没有回收子进程的相关资源,该子进程即成为僵尸进程。
  2. 进程标识符 (进程 ID)

    1. 每个进程都有一个以非负整数表示的唯一标识,即进程 ID/PID。
    2. 进程 ID 在任何时刻都是唯一的,但可以重用,当一个进程退出时,其进程 ID 就可以被其它进程使用。
    3. 延迟重用。
      a.out - 1000
      a.out - 1010
      a.out - 1020
      范例:delay.c



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

int main () 
{
    printf ("进程ID:%u\n", getpid ());
    return 0;
}

二、getxxxid

#include <unistd.h>
getpid  - 获取进程ID
getppid - 获取父进程ID
getuid  - 获取实际用户ID
geteuid - 获取有效用户ID
getgid  - 获取实际组ID
getegid - 获取有效组ID

范例:id.c

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

int main () 
{
    printf ("    进程ID:%u\n", getpid ());
    printf ("  父进程ID:%u\n", getppid ());
    printf ("实际用户ID:%u\n", getuid ());
   printf ("有效用户ID:%u\n", geteuid ());
    printf ("  实际组ID:%u\n", getgid ());
    printf ("  有效组ID:%u\n", getegid ());

    return 0;
}

三、fork

#include <unistd.h>
pid_t fork (void);
  1. 创建一个子进程,失败返回 - 1
  2. 调用一次,返回两次
    分别在父子进程中返回子进程的 PID 和 0。
    用返回值的不同,可以分别为父子进程编写不同的处理分支。
    范例:fork.c


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

int main () 
{
    printf ("%u进程:我要调用fork()了...\n", getpid ());

    pid_t pid = fork ();
    if (pid == -1) 
    {
        perror ("fork");
        return -1;
    }

    if (pid == 0) 
    {
        printf ("%u进程:我是%u进程的子进程。\n", getpid (),
            getppid ());
        return 0;
    }

    printf ("%u进程:我是%u进程的父进程。\n", getpid (), pid);
    sleep (1);

    return 0;
}
  1. 子进程是父进程的副本
    子进程获得父进程数据段和堆栈段 (包括 I/O 流缓冲区) 的拷贝,但子进程共享父进程的代码段。
    范例:mem.c、os.c、is.c 、mem.c

mem.c

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

int global = 100;

int main () 
{
    int local = 200;

    char* heap = (char*)malloc (256 * sizeof (char));
    sprintf (heap, "ABC");

    printf ("父进程:%d %d %s\n", global, local, heap);

    pid_t pid = fork ();
    if (pid == -1) 
    {
        perror ("fork");
        return -1;
    }

    if (pid == 0) 
    {
        global++;
        local++;
        sprintf (heap, "XYZ");
        printf ("子进程:%d %d %s\n", global, local, heap);
        free (heap);

        return 0;
    }

    sleep (1);
    printf ("父进程:%d %d %s\n", global, local, heap);
    free (heap);

    return 0;
}

os.c

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

int main () 
{
    printf ("ABC");

    pid_t pid = fork ();
    if (pid == -1) 
    {
        perror ("fork");
        return -1;
    }

    if (pid == 0) 
    {
        printf ("XYZ\n");
        return 0;
    }

    sleep (1);
    printf ("\n");

    return 0;
}
  1. 函数调用后父子进程各自继续运行
    其先后顺序不确定 , 某些实现可以保证子进程先被调度。
  2. 共享文件表
    函数调用后,父进程的文件描述符表 (进程级) 也会被复制到子进程中,二者共享同一个文件表 (内核级)。
    范例:ftab.c

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main () 
{
    int fd = open ("ftab.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) 
    {
        perror ("open");
        return -1;
    }

    const char* text = "Hello, World !";
    if (write (fd, text, strlen (text) * sizeof (text[0])) == -1) 
    {
        perror ("write");
        return -1;
    }

    pid_t pid = fork ();
    if (pid == -1) 
    {
        perror ("fork");
        return -1;
    }

    if (pid == 0) 
    {
        if (lseek (fd, -7, SEEK_CUR) == -1) 
        {
            perror ("lseek");
            return -1;
        }

        close (fd);

        return 0;
    }

    sleep (1);

    text = "Linux";
    if (write (fd, text, strlen (text) * sizeof (text[0])) == -1) 
    {
        perror ("write");
        return -1;
    }

    close (fd);

    return 0;
}

  1. 总进程数或实际用户 ID 所拥有的进程数,超过系统限制,该函数将失败。
  2. 一个进程如果希望创建自己的副本并执行同一份代码,或希望与另一个程序并发地运行,都可以使用该函数。
  3. 孤儿进程与僵尸进程。
    范例:orphan.c、zombie.c
    orphan.c

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

int main (void) 
{
    printf ("%u进程:我要调用fork()了...\n", getpid ());

    pid_t pid = fork ();
    if (pid == -1) 
    {
        perror ("fork");
        return -1;
    }

    if (pid == 0) 
    {
        sleep (1);
        printf ("\n%u进程:我是被%u进程收养的孤儿进程。", getpid (),
            getppid ());

        return 0;
    }

    printf ("%u进程:我是%u进程的父进程。\n", getpid (), pid);

    return 0;
}

zombie.c

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

int main () 
{
    printf ("%u进程:我要调用fork()了...\n", getpid ());

    pid_t pid = fork ();
    if (pid == -1) 
    {
        perror ("fork");
        return -1;
    }

    if (pid == 0)
    {
        printf ("%u进程:我是%u进程的子进程,即将成为僵尸...\n",
            getpid (), getppid ());
        return 0;
    }

    sleep (1);
    printf ("%u进程:我是%u进程的父进程。\n", getpid (), pid);

    printf ("执行ps -efl | grep %u,按<回车>退出...", pid);
    getchar ();

    return 0;
}

注意:fork 之前的代码只有父进程执行,fork 之后的代码父子进程都有机会执行,受代码逻辑的控制而进入不同分支。

四、vfork

#include <unistd.h>
pid_t vfork (void);

该函数的功能与 fork 基本相同,二者的区别:

  1. 调用 vfork 创建子进程时并不复制父进程的地址空间
    子进程可以通过 exec 函数族,直接启动另一个进程替换自身,进而提高进程创建的效率。
  2. vfork 调用之后,子进程先被调度

五、进程的正常退出

  1. 从 main 函数中 return。
    int main (…)
    {

    return x;
    }
    等价于:
    int main (…)
    {

    exit (x);
    }










  2. 调用标准 C 语言的 exit 函数。

     #include <stdlib.h>
     void exit (int status);
    
    1. 调用进程退出
      其父进程调用 wait/waitpid 函数返回 status 的低 8 位。

    2. 进程退出之前
      先调用所有事先通过 atexit/on_exit 函数注册的函数,
      冲刷并关闭所有仍处于打开状态的标准 I/O 流,
      删除所有通过 tmpfile 函数创建的文件。


    3. 用 EXIT_SUCCESS/EXIT_FAILURE 常量宏 (可能是 0/1) 作参数,调用 exit () 函数表示成功 / 失败,提高平台兼容性。

    4. 该函数不会返回。

    5. 该函数的实现调用了_exit/_Exit 函数。

       #include <stdlib.h>
       int atexit (void (*function) (void));
       function - 函数指针,
      指向进程退出前需要被调用的函数。
      该函数既没有返回值也没有参数。
       成功返回0,失败返回非零。
      
       int on_exit (void (*function) (int, void*), void* arg);
       function - 函数指针,
      指向进程退出前需要被调用的函数。
      该函数没有返回值但有两个参数:
      第一参数来自exit函数的status参数,
      第二个参数来自on_exit函数的arg参数。
       arg      - 任意指针,
      将作为第二个参数被传递给function所指向的函数。
       成功返回0,失败返回非零。
      
  3. 调用_exit/_Exit 函数

     #include <unistd.h>
     void _exit (int status);
     该函数有一个完全等价的标准C版本:
     #include <stdlib.h>
     void _Exit (int status);
    
  4. 进程的最后一个线程执行了返回语句。

  5. 进程的最后一个线程调用 pthread_exit 函数。

六、进程的异常终止

  1. 调用 abort 函数,产生 SIGABRT 信号
  2. 进程接收到某些信号 (kill -9)
  3. 最后一个线程对 “取消” 请求做出响应 (pthread_exit())。

七、wait/waitpid

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait (int* status);

pid_t waitpid (pid_t pid, int* status, int options);
  1. 当一个进程正常或异常终止时,内核向其父进程发送 SIGCHLD 信号。

父进程可以忽略该信号,或者提供一个针对该信号的信号处理函数,默认为忽略。

  1. 父进程调用 wait 函数:

    1. 若所有子进程都在运行,则阻塞。
    2. 若有一个子进程已终止,则返回该子进程的 PID 和终止状态 (通过 status 参数)。
    3. 若没有需要等待子进程,则返回失败,errno 为 ECHILD。
    1. 在任何一个子进程终止前,wait 函数只能阻塞调用进程,而 waitpid 函数可以有更多选择。

    2. 如果有一个子进程在 wait 函数被调用之前,已经终止并处于僵尸状态,wait 函数会立即返回,并取得该子进程的终止状态。

    3. 子进程的终止状态通过输出参数 status 返回给调用者,若不关心终止状态,可将此参数置空。

    4. 子进程的终止状态可借助 sys/wait.h 中定义的参数宏查看:
      •WIFEXITED()
      子进程是否正常终止,是则通过 WEXITSTATUS () 宏,获取子进程调用 exit/_exit/_Exit 函数,所传递参数的低 8 位。
      因此传给 exit/_exit/_Exit 函数的参数最好不要超过 255。
      •WIFSIGNALED()
      子进程是否异常终止,是则通过 WTERMSIG () 宏获取终止子进程的信号。
      •WIFSTOPPED()
      子进程是否处于暂停,是则通过 WSTOPSIG () 宏获取暂停子进程的信号。
      •WIFCONTINUED()
      子进程是否在暂停之后继续运行
      范例:wait.c、loop.c
      wait.c










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

int main () 
{
    pid_t pid = fork ();
    if (pid == -1) 
    {
        perror ("fork");
        return -1;
    }

    if (pid == 0) 
    {
        int status = 0x12345678;

        printf ("子进程:我是%u进程。我要以%#x状态退出。\n",
            getpid (), status);

        return status;
    }

   printf ("父进程:我要等待子进程...\n");

    int status;
    pid = wait (&status);

    printf ("父进程:发现%u进程以%#x状态退出了。\n", pid,
.        WEXITSTATUS (status));

    return 0;
}

loop.c

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

int main () 
{
    int i;
    for (i = 0; i < 3; i++) 
    {
        pid_t pid = fork ();
        if (pid == -1) 
        {
            perror ("fork");
            return -1;
        }

        if (pid == 0) 
        {
            printf ("子进程:我是%u进程。我要退出了。\n", getpid ());
            return 0;
        }
    }

    for (;;) 
    {
        printf ("父进程:我要等待子进程...\n");

        pid_t pid = wait (0);
        if (pid == -1) 
        {
            if (errno != ECHILD) 
            {
                perror ("wait");
                return -1;
            }

            printf ("父进程:已经没有子进程可等了,走喽!\n");
            break;
        }

        printf ("父进程:发现%u进程退出了。\n", pid);
    }

    return 0;
}
  1. 如果同时存在多个子进程,又需要等待特定的子进程,可使用 waitpid 函数,其 pid 参数:

     -1 - 等待任一子进程,此时与wait函数等价。
     > 0 - 等待由该参数所标识的特定子进程。
      0 - 等待其组ID等于调用进程组ID的任一子进程,即等待与调用进程同进程组的任一子进程。
     <-1 - 等待其组ID等于该参数绝对值的任一子进程,即等待隶属于特定进程组内的任一子进程。
    

范例:waitpid.c

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

int main () 
{
    pid_t cpid[3];
    int i;
    for (i = 0; i < sizeof (cpid) / sizeof (cpid[0]); i++) 
    {
        cpid[i] = fork ();
        if (cpid[i] == -1) 
        {
            perror ("fork");
            return -1;
        }

        if (cpid[i] == 0) 
        {
            printf ("子进程:我是%u进程。我要退出了。\n", getpid ());
            return 0;
        }
    }

    for (i = 0; i < sizeof (cpid) / sizeof (cpid[0]); i++) 
    {
        printf ("父进程:我要等待%u进程...\n", cpid[i]);

        pid_t pid = waitpid (cpid[i], 0, 0);
        if (pid == -1) 
        {
            perror ("waitpid");
            return -1;
        }

        printf ("父进程:发现%u进程退出了。\n", pid);
    }

    return 0;
}

  1. waitpid 函数的 options 参数可取 0 (忽略) 或以下值的位或:

     •WNOHANG 
     非阻塞模式,若没有可用的子进程状态,则返回0。 
     	◦WUNTRACED 
     	若支持作业控制,且子进程处于暂停态,则返回其状态。
     	◦WCONTINUED 
     	若支持作业控制,且子进程暂停后继续,则返回其状态。
    

范例:nohang.c

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

int main (void) 
{
    int i;
    for (i = 0; i < 3; i++) 
    {
        pid_t pid = fork ();
        if (pid == -1) 
        {
            perror ("fork");
            return -1;
        }

        if (pid == 0) 
        {
            printf ("子进程:我是%u进程。我要退出了。\n", getpid ());
            return 0;
        }
    }

    for (;;) 
    {
        printf ("父进程:我要等待子进程...\n");

        pid_t pid = waitpid (-1, 0, WNOHANG);
        if (pid == -1) 
        {
            if (errno != ECHILD) 
            {
                perror ("waitpid");
                return -1;
            }

            printf ("父进程:已经没有子进程可等了,走喽!\n");
            break;
        }

        if (pid)
            printf ("父进程:发现%u进程退出了。\n", pid);
        else
            printf ("父进程:没发现子进程退出,干点儿别的...\n");
    }

    return 0;
}

八、exec

1、exec 函数会用新进程完全替代调用进程,并开始从 main 函数执行。

2、exec 函数并非创建子进程,新进程取调用进程的 PID。

3、exec 函数所创建的新进程,完全取代调用进程的代码段、数据段和堆栈段。

4、exec 函数若执行成功,则不会返回,否则返回 - 1。

5、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[]
);

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

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

l: 新程序的命令参数以单独字符串指针的形式传入(const char* arg, ...),参数表以空指针结束。
v: 新程序的命令参数以字符串指针数组的形式传入(char* const argv[]),数组以空指针结束。
e: 新程序的环境变量以字符串指针数组的形式传入(char* const envp[]),数组以空指针结束,无e则从调用进程的environ变量中复制。
p: 若第一个参数中不包含“/”,则将其视为文件名,根据PATH环境变量搜索该文件。

范例:argenv.c、exec.c
argenv.c

#include <stdio.h>

void printarg (int argc, char* argv[]) 
{
    printf ("---- 命令参数 ----\n");

    int i;
    for (i = 0; i < argc; i++)

       printf ("argv[%d] = %s\n", i, argv[i]);

    printf ("------------------\n");
}

void printenv () 
{
    printf ("---- 环境变量 ----\n");

    extern char** environ;
    char** env;
    for (env = environ; env && *env; env++)
        printf ("%s\n", *env);

    printf ("------------------\n");
}

int main (int argc, char* argv[]) 
{
    printarg (argc, argv);
    printenv ();

    return 0;
}

exec.c

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

int main (void) 
{
    char* path = "./argenv";
    char* file = "argenv";
    char* argv[] = {path, "hello", "world", NULL};
    char* envp[] = {"USER=unknown", "PATH=/tmp", NULL};
    /*
    if (execl (path, argv[0], argv[1], argv[2], argv[3]) == -1) 
    {
        perror ("execl");
        return -1;
    }
    *//*
    if (execv (path, argv) == -1) 
    {
        perror ("execv");
        return -1;
    }
    *//*
    if (execle (path, argv[0], argv[1], argv[2], argv[3], envp) == -1) 
    {
        perror ("execle");
        return -1;
    }
    *//*
    if (execve (path, argv, envp) == -1) 
    {
        perror ("execve");
        return -1;
    }
    *//*
    if (execlp (file, argv[0], argv[1], argv[2], argv[3]) == -1) 
    {
        perror ("execlp");
        return -1;
    }
    */
    if (execvp (file, argv) == -1) 
    {
        perror ("execvp");
        return -1;
    }

    return 0;
}

九、system

#include <stdlib.h>
int system (const char* command);
  1. 标准 C 函数。执行 command,成功返回 command 对应进程的终止状态,失败返回 - 1。
  2. 若 command 取 NULL,返回非零表示 shell 可用,返回 0 表示 shell 不可用。
  3. 该函数的实现,调用了 fork、exec 和 waitpid 等函数,其返回值:
    1. 如果调用 fork 或 waitpid 函数出错,则返回 - 1。
    2. 如果调用 exec 函数出错,则在子进程中执行 exit (127)。
    3. 如果都成功,则返回 command 对应进程的终止状态 (由 waitpid 的 status 输出参数获得)。
    4. 用 system 函数而不用 fork+exec 的好处是,system 函数针对各种错误和信号都做了必要的处理。

Linux - 系统 - 进程管理

Linux - 系统 - 进程管理

吴宏东 - 记于2018年06月19日 - 博客 https://segmentfault.com/u/wu...

Linux 进程管理

进程概述

父子进程

PID:进程的唯一标识号;
systemd:系统启动后第一个进程,PID=1;
login:systemd进程会创建login进程,所以,systemd是login的父进程,反之login是systemd的子进程;
shell:shell(默认是bash)是login进程创建的,其后用户的所有进程都由该进程派生创建;

进程标识

RUID:实际用户识别号;
RGID:实际组识别号;
EUID:有效用户识别号;
EGID:有效组识别号;
RUID和RGID的作用是识别正在运行此进程的用户和组;
如果程序没有设置SUID和SGID,那么EUID和EGID就是RUID和RGID,而RUID和RGID就是用户和组的UID和GID;

进程类型

交互进程:由shell启动的进程,可以前台或后台运行;
批处理进程:不与特定终端关联,加入后台的计划队列顺序处理;
守护进程:系统初始化后,需要运行于后台的进程;

查看进程

命令 ps -aux

[-a]:显示所有进程;
[-u]:显示用户名和启动时间等信息;
[-x]:显示没有控制终端的进程;
[-w]:显示完整命令行;

# 查找关于openshift的进程
ps -aux|grep openshift;
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.1 128020  6620 ?        Ss   10:33   0:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root          2  0.0  0.0      0     0 ?        S    10:33   0:00 [kthreadd]
root          3  0.0  0.0      0     0 ?        S    10:33   0:00 [ksoftirqd/0]
root          5  0.0  0.0      0     0 ?        S<   10:33   0:00 [kworker/0:0H]
root          6  0.0  0.0      0     0 ?        S    10:33   0:01 [kworker/u256:0]

USER:用户名;
PID:进程号;
%CPU:占用CPU时间与总时间的百分比;
%MEM:占用内存与系统内存总量的百分比;
VSZ:占用虚拟内存空间,单位KB;
RSS:占用内存空间,单位KB;
TTY:从哪个终端启动;
STAT:进程当前状态;
START:开始执行时间;
TIME:自启动以来占用CPU的总时间;
COMMAND:启动命令名;

状态:R 执行中;S 睡眠;T 追踪或停止;Z 僵尸进程;< 高优先级;N 低优先级;

命令 pgrep

通过模糊匹配模式,查找进程的ID

# 查找关于openshift的进程ID
pgrep openshift;

命令 pidof

通过模糊匹配模式,查找进程的ID

# 查找关于openshift的进程ID
pidof openshift;

杀死进程

命令 kill

# 杀死指定PID为10086的进程
kill 10086;
# 强制杀死进程
kill -9 10086;
# 杀死进程名为openshift的进程
kill openshift;
kill -9 $(pgrep openshift);

命令 killall

# 杀死进程名为openshift的所有进程
killall openshift;

命令 pkill

# 杀死进程名为openshift的所有进程
pkill openshift;

作业进程

cmd &:表示后台执行;
nohup cmd &:表示后台执行,并且用户注销后仍然运行着;
<Ctrl+D>:正常终止一个前台运行的进程;
<Ctrl+C>:强行终止一个前台运行的进程;
<Ctrl+Z>:挂起一个正在前台运行的进程;
<Ctrl+S>:挂起终端;
<Ctrl+Q>:解除挂起终端;

命令 [cmd] &

# 终端休眠100秒,调度到后台运行
sleep 100 &;

命令 nohup [cmd] &

# 终端休眠100秒,调度到后台运行,且用户注销后仍然运行着
nohup sleep 100 &;

命令 jobs

# 查看正在运行的作业
jobs;
# 显示进程PID
jobs -l;
[root@master ~]# jobs -l
[1]+  1810 完成                  sleep 100

[1] 是作业序号;
1810 是进程PID;
sleep 100 是命令;

命令 fg %

# 将作业[1]调度到前台终端运行
fg %1;

命令 bg %

# 将作业[1]调度到后台终端运行
bg %1;

命令 kill %

# 将作业[1]进程杀死
kill %1;

Linux - 进程管理 和用户管理

Linux - 进程管理 和用户管理

进程命令管理

进程:二进制加载到内存中,CPU执行期中指令整个过程
进程一定是运行中的程序
图片.png
PID 进程ID号

查看进程

ps :简略查看进程
top:动态查看进程
pstree:树状查看进程

图片.png

[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18501 pts/0    00:00:00 ps


[root@localhost 2020-3-13]# top
top - 17:55:23 up 108 days, 20:23,  1 user,  load average: 0.00,
Tasks:  64 total,   1 running,  63 sleeping,   0 stopped,   0 zo
%Cpu(s):  0.7 us,  0.3 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  
KiB Mem :  1883496 total,   685784 free,    78456 used,  1119256
KiB Swap:        0 total,        0 free,        0 used.  1617020

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM 
29804 root      10 -10  125024  12516   9608 S  1.0  0.7 
  777 root      20   0  562388  16564   5876 S  0.3  0.9 
29730 root      10 -10   32612   4344   2780 S  0.3  0.2 
    1 root      20   0   51460   3680   2516 S  0.0  0.2 
    2 root      20   0       0      0      0 S  0.0  0.0 
    3 root      20   0       0      0      0 S  0.0  0.0 
    5 root       0 -20       0      0      0 S  0.0  0.0 
    7 root      rt   0       0      0      0 S  0.0  0.0 
    8 root      20   0       0      0      0 S  0.0  0.0 
    9 root      20   0       0      0      0 S  0.0  0.0 
   10 root      rt   0       0      0      0 S  0.0  0.0 
   12 root      20   0       0      0      0 S  0.0  0.0 
   13 root       0 -20       0      0      0 S  0.0  0.0 
   14 root      20   0       0      0      0 S  0.0  0.0 
   
   
[root@localhost 2020-3-13]# pstree
systemd─┬─AliYunDun───23*[{AliYunDun}]
        ├─AliYunDunUpdate───3*[{AliYunDunUpdate}]
        ├─2*[agetty]
        ├─aliyun-service───2*[{aliyun-service}]
        ├─atd
        ├─auditd───{auditd}
        ├─crond
        ├─dbus-daemon
        ├─dhclient
        ├─ntpd
        ├─polkitd───5*[{polkitd}]
        ├─rsyslogd───2*[{rsyslogd}]
        ├─sshd───sshd───bash───pstree
        ├─systemd-journal
        ├─systemd-logind
        ├─systemd-udevd
        └─tuned───4*[{tuned}]

杀死进程

图片.png

kill举例

Terminated :结束,终点

[root@localhost 2020-3-13]# sleep 1000 &
[1] 18529
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18529 pts/0    00:00:00 sleep
18530 pts/0    00:00:00 ps
[root@localhost 2020-3-13]# kill 18529
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18531 pts/0    00:00:00 ps
[1]+  Terminated              sleep 1000

pkill举例

[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18537 pts/0    00:00:00 ps
[root@localhost 2020-3-13]# sleep 1000 &
[1] 18538
[root@localhost 2020-3-13]# sleep 1000 &
[2] 18539
[root@localhost 2020-3-13]# sleep 1000 &
[3] 18540
[root@localhost 2020-3-13]# sleep 1000 &
[4] 18541
[root@localhost 2020-3-13]# sleep 1000 &
[5] 18542
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18538 pts/0    00:00:00 sleep
18539 pts/0    00:00:00 sleep
18540 pts/0    00:00:00 sleep
18541 pts/0    00:00:00 sleep
18542 pts/0    00:00:00 sleep
18543 pts/0    00:00:00 ps
[root@localhost 2020-3-13]# pkill sleep
[1]   Terminated              sleep 1000
[2]   Terminated              sleep 1000
[3]   Terminated              sleep 1000
[4]-  Terminated              sleep 1000
[5]+  Terminated              sleep 1000
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18547 pts/0    00:00:00 ps

更改进程(前台执行/后台执行)

末尾加上& ,表示挂在后台执行
jobs显示后台任务
图片.png

[root@localhost 2020-3-13]# sleep 100
^C
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18507 pts/0    00:00:00 ps
[root@localhost 2020-3-13]# sleep 100 &
[1] 18513
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18513 pts/0    00:00:00 sleep
18514 pts/0    00:00:00 ps

转到前台举例

[root@localhost 2020-3-13]# jobs
[root@localhost 2020-3-13]# sleep 1000 &
[1] 18549
[root@localhost 2020-3-13]# jobs
[1]+  Running                 sleep 1000 &
[root@localhost 2020-3-13]# sleep 1000 &
[2] 18550
[root@localhost 2020-3-13]# jobs
[1]-  Running                 sleep 1000 &
[2]+  Running                 sleep 1000 &
[root@localhost 2020-3-13]# fg 1
sleep 1000
^C
[root@localhost 2020-3-13]# jobs
[2]+  Running                 sleep 1000 &

用户管理

图片.png
图片.png

添加/删除用户

主组:默认下,每个用户默认创建的基本组
附加组:除了基本组外,用户可以属于的其他组
一个用户可以有很多组,但是主组只有一个.其余都是附加组

图片.png

/etc/passwd 文件

-g 指定用户的主组

stu 用户id:1001,组id:1001
stu3:用户id:1003,组id:1001
stu和stu3的主组是同一组 stu

[root@localhost home]# useradd -g stu stu3
[root@localhost home]# cat /etc/passwd | grep stu
stu:x:1001:1001::/home/stu:/bin/bash
stu2:x:1002:1002::/home/stu2:/bin/bash
stu3:x:1003:1001::/home/stu3:/bin/bash

/etc/group 文件

-G 指定用户所属附加组

stu除了主组外,TA的附加组 是stu2

[root@localhost home]# useradd -G stu stu2
[root@localhost home]# cat /etc/group | grep stu
Akuaner:x:1000:stu
stu:x:1001:stu2
stu2:x:1002:

/etc/shadow 文件

passwd 设置密码

新建用户无密码

[root@localh home]# cat /etc/shadow | grep stu3
stu3:!!:18336:0:99999:7:::
[root@localh home]# passwd stu3
Changing password for user stu3.
New password: 
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@localh home]# cat /etc/shadow | grep stu3
stu3:$6$shDnKXpO$x.pN6HZDwGp0MmKXEMbYPpdkGkb/lAITw.fnzxNmVb0ZoSifWFnKS.PQP1KW5lE9b8eFhrWyQGzHk0nySlAN2/:18336:0:99999:7:::

Linux - 进程管理,ps 与 top

Linux - 进程管理,ps 与 top

一个运行的程序,可能有多个进程。

PID 进程 ID。

UID 启动进程的 ID。

进程所属组 GID。

进程的状态 R 运行、S 睡眠、Z 僵尸。

父进程管理子进程,父进程终止的时候子进程也会终止。

常用的组合为:

ps aux | ps -aux

字段含义:

USER:用户名称 
PID:进程号 
%CPU:进程占用CPU的百分比 
%MEM:进程占用物理内存的百分比 
VSZ:进程占用的虚拟内存大小(单位:KB) 
RSS:进程占用的物理内存大小(单位:KB) 
TT:终端名称(缩写),若为?,则代表此进程与终端无关,因为它们是由系统启动的 
STAT:进程状态,其中S-睡眠,s-表示该进程是会话的先导进程,N-表示进程拥有比普通优先级更低的优先级,R-正在运行,D-短期等待,Z-僵死进程,T-被跟踪或者被停止等等 
STARTED:进程的启动时间 
TIME:CPU时间,即进程使用CPU的总时间 
COMMAND:启动进程所用的命令和参数,如果过长会被截断显示 
ps -ef

字段含义:

UID:用户ID 
PID:进程ID 
PPID:父进程ID 
C:CPU用于计算执行优先级的因子。数值越大,表明进程是CPU密集型运算,执行优先级会降低;数值越小,表明进程是I/O密集型运算,执行优先级会提高 
STIME:进程启动的时间 
TTY:完整的终端名称 
TIME:CPU时间 
CMD:完整的启动进程所用的命令和参数

如果想查看进程的 CPU 占用率和内存占用率,可以使用 aux 如果想查看进程的父进程 ID 和完整的 COMMAND 命令,可以使用 ef

top 动态的查看进程。

父进程死了,子进程没死,就形成了僵尸进程。会影响系统性能。

默认 3s 刷新一次。

空格立即刷新。

q 退出。

M 按内存排序。

P 按 CPU 排序。

Linux c 进程管理 — 创建进程 system、execl、execlp、fork

Linux c 进程管理 — 创建进程 system、execl、execlp、fork

Linux c 进程管理:
 
1.      创建进程:
       system函数:
        int system(const char*filename);
                                                 建立独立进程,拥有独立的代码空间,内存空间
                                                 等待新的进程执行完毕,system才返回.(阻塞)
         system:创建一个堵塞的新进程,新进程结束后,system才返回
 
         案例:
              使用system调用一个程序。
                    观察进程ID。
                    观察阻塞。
 
代码:
text.c
 
#include<stdio.h>
#include<unistd.h>
 
void  main()
{
      printf(“%d\n”,getpid());    //打印当前进程id
      sleep(10);               //进程睡眠10秒
}
 
gcctext.c –o text
 
system.c
 
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
 
void  main()
{
     printf(“%d\n”,getpid());
     int r=system(“./text”);
     printf(“%d\n”,r);
}
 
gccsystem.c –o main
 
结论:
     新进程的返回值与system返回值有关系。
        任何进程的返回值:不要超过255。一个字节。
        system的返回值中8-15位存放返回码(一个字节存放返回码)
     要想得到返回码,则不能直接用system的返回值,要取返回值的8-15位的内容。
     Linux提供一个宏来获取该值WEXITSTATUS(status)、包含在#include<sys/wait.h>
 
代码:
 
text.c
 
#include<stdio.h>
#include<unistd.h>
 
int  main()
{
      printf(“%d\n”,getpid());    //打印当前进程id
      sleep(10);             //进程睡眠10秒
      return 99;
}
 
gcctext.c –o text
 
system.c
 
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
 
void  main()
{
     printf(“%d\n”,getpid());
     int r=system(“./text”);
     printf(“%d\n”,WEXITSTATUS(r));
}
 
gccsystem.c –o main
 
 
 
 
 
 
 
popen函数:
   #include<stdio.h>
   函数原型:
   FILE * popen ( constchar * command , const char * type );
int pclose ( FILE * stream );
 
popen:创建子进程
在父子进程之间建立一个管道
command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c 标志,shell将执行这个命令。
type: 只能是读或者写中的一种,得到的返回值(标准I/O 流)也具有和 type 相应的只读或只写类型。如果type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到command 的标准输入。
返回值:
  如果调用成功,则返回一个读或者打开文件的指针,如果失败,返回NULL,具体错误要根据errno判断
  int pclose (FILE*stream)
  参数说明:
  stream:popen返回的文件指针
  返回值:
  如果调用失败,返回 -1
 
案例:
使用popen调用ls -l,并且建立一个管道读取输出
 
#include<stdio.h>
#include<unistd.h>
 
void main()
{
     char buf[1024];
     FILE *f=popen(“ls - l”,”r”);
     int fd=fileno(f);
     int r;
     while((r=read(fd,buf,1024))>0)
     {
            buf[r]=0;
          printf(“%s”,buf);
     }
     close(fd);
     pclose(f);
}
 
execlexecle:
          代替当前进程的代码空间中的代码数据,函数本身不创建新的进程。
 
excel函数:
int execl(const char * path,const char*arg,….);
第一个参数:替换的程序
第二个参数…..:命令行
                      命令行格式:命令名 选项参数
                      命令行结尾必须空字符串结尾
 
案例:
                     使用exec执行一个程序。
                     体会:*是否创建新的进程?没有
                              *体会execl的参数的命令行的格式
                              *体会execl与execlp的区别(execl只当前路径)(不是当前路径必须加绝对路径)
                                                               execlp使用系统的搜索路径
                               *体会execl替换当前进程的代码
 
代码:
 
text.c
 
#include<stdio.h>
#include<unistd.h>
 
void  main()
{
      printf(“%d\n”,getpid());    //打印当前进程id
      sleep(10);             //进程睡眠10秒
   
}
 
gcctext.c –o text
 
 
 
 
exec.c
 
#include<stdio.h>
#include<unistd.h>
 
 
void  main()
{
       printf(“main::%d\n”,getpid());
       int r=excel(“./text”,”text”,NULL);
       //int r=excel(“/bin/ls”,”ls”,”-l”,NULL);
       //int r=excelp(“ls”,”ls”,”-l”,NULL);
       printf(“结束:%d\n”,r);
}
 
总结:
程序运行后,两个打印进程id是一样,则excel和execlp不创建新的进程。
最后的打印结束的语句不能执行,因为excel和excelp是将新的程序的代码替换到该程序的代码空间中了。
两个函数的最后一个参数必须为0NULL
函数的第一个参数是可执行程序的路径,第二个参数才是执行的命令
 
 
fork函数:
函数原型:
         pid_t  fork(); //1.创建进程
                     //2.新进程的代码是什么:克隆父进程的代码
                                                        而且克隆了执行的位置.(从父进程复制过来的代码,fork之前的代码不会再子进程中执行,子进程只会执行从父进程复制过来的fork以后的代码)
                     //3.在子进程不调用fork所以返回值=0;(pid=0为子进程的)
                                    //4.父子进程同时执行.
 
例子代码:
#include<stdio.h>
#include<unistd.h>
 
void  main()
{
      printf(“创建进程之前\n”);
      int pid=fork();
      printf(“创进程之后%d\n”,pid);
}
 
虽然子进程的代码是克隆父进程的,但我们也可以把子进程要执行的代码和父进程要执行的代码分开。
 
例子:
#include<stdio.h>
#include<unistd.h>
 
voidmain()
{
      printf(“创建进程之前:\n”);
      int pid=fork();
      if(pid==0)
      {
           printf(“子进程:\n”);
      }
      else
      {
           printf(“父进程:\n”);
      }
}

关于UNIX-Linux 环境编程五:进程管理的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于Linux - 系统 - 进程管理、Linux - 进程管理 和用户管理、Linux - 进程管理,ps 与 top、Linux c 进程管理 — 创建进程 system、execl、execlp、fork等相关内容,可以在本站寻找。

本文标签: