如果您想了解UNIX-Linux环境编程和五:进程管理的知识,那么本篇文章将是您的不二之选。我们将深入剖析UNIX-Linux环境编程的各个方面,并为您解答五:进程管理的疑在这篇文章中,我们将为您介绍
如果您想了解UNIX-Linux 环境编程和五:进程管理的知识,那么本篇文章将是您的不二之选。我们将深入剖析UNIX-Linux 环境编程的各个方面,并为您解答五:进程管理的疑在这篇文章中,我们将为您介绍UNIX-Linux 环境编程的相关知识,同时也会详细的解释五:进程管理的运用方法,并给出实际的案例分析,希望能帮助到您!
本文目录一览:- UNIX-Linux 环境编程(五):进程管理(linux进程管理命令使用)
- Linux - 系统 - 进程管理
- Linux - 进程管理 和用户管理
- Linux - 进程管理,ps 与 top
- Linux c 进程管理 — 创建进程 system、execl、execlp、fork
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: 进程被绑定到哪个处理器。
-
父进程、子进程、孤儿进程和僵尸进程
- 父进程启动子进程后,子进程在操作系统的调度下与其父进程同时运行。
- 子进程先于父进程结束,子进程向父进程发送 SIGCHLD (17) 信号,父进程回收子进程的相关资源。
- 父进程先于子进程结束,子进程成为孤儿进程,同时被 init 进程收养,即成为 init 进程的子进程。
- 子进程先于父进程结束,但父进程没有回收子进程的相关资源,该子进程即成为僵尸进程。
-
进程标识符 (进程 ID)
- 每个进程都有一个以非负整数表示的唯一标识,即进程 ID/PID。
- 进程 ID 在任何时刻都是唯一的,但可以重用,当一个进程退出时,其进程 ID 就可以被其它进程使用。
- 延迟重用。
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
- 调用一次,返回两次
分别在父子进程中返回子进程的 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;
}
- 子进程是父进程的副本
子进程获得父进程数据段和堆栈段 (包括 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;
}
- 函数调用后父子进程各自继续运行
其先后顺序不确定 , 某些实现可以保证子进程先被调度。 - 共享文件表
函数调用后,父进程的文件描述符表 (进程级) 也会被复制到子进程中,二者共享同一个文件表 (内核级)。
范例: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;
}
- 总进程数或实际用户 ID 所拥有的进程数,超过系统限制,该函数将失败。
- 一个进程如果希望创建自己的副本并执行同一份代码,或希望与另一个程序并发地运行,都可以使用该函数。
- 孤儿进程与僵尸进程。
范例: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 基本相同,二者的区别:
- 调用 vfork 创建子进程时并不复制父进程的地址空间
子进程可以通过 exec 函数族,直接启动另一个进程替换自身,进而提高进程创建的效率。 - vfork 调用之后,子进程先被调度。
五、进程的正常退出
-
从 main 函数中 return。
int main (…)
{
…
return x;
}
等价于:
int main (…)
{
…
exit (x);
} -
调用标准 C 语言的 exit 函数。
#include <stdlib.h> void exit (int status);
-
调用进程退出
其父进程调用 wait/waitpid 函数返回 status 的低 8 位。 -
进程退出之前
先调用所有事先通过 atexit/on_exit 函数注册的函数,
冲刷并关闭所有仍处于打开状态的标准 I/O 流,
删除所有通过 tmpfile 函数创建的文件。 -
用 EXIT_SUCCESS/EXIT_FAILURE 常量宏 (可能是 0/1) 作参数,调用 exit () 函数表示成功 / 失败,提高平台兼容性。
-
该函数不会返回。
-
该函数的实现调用了_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,失败返回非零。
-
-
调用_exit/_Exit 函数
#include <unistd.h> void _exit (int status); 该函数有一个完全等价的标准C版本: #include <stdlib.h> void _Exit (int status);
-
进程的最后一个线程执行了返回语句。
-
进程的最后一个线程调用 pthread_exit 函数。
六、进程的异常终止
- 调用 abort 函数,产生 SIGABRT 信号。
- 进程接收到某些信号 (kill -9)。
- 最后一个线程对 “取消” 请求做出响应 (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);
- 当一个进程正常或异常终止时,内核向其父进程发送 SIGCHLD 信号。
父进程可以忽略该信号,或者提供一个针对该信号的信号处理函数,默认为忽略。
-
父进程调用 wait 函数:
- 若所有子进程都在运行,则阻塞。
- 若有一个子进程已终止,则返回该子进程的 PID 和终止状态 (通过 status 参数)。
- 若没有需要等待子进程,则返回失败,errno 为 ECHILD。
-
在任何一个子进程终止前,wait 函数只能阻塞调用进程,而 waitpid 函数可以有更多选择。
-
如果有一个子进程在 wait 函数被调用之前,已经终止并处于僵尸状态,wait 函数会立即返回,并取得该子进程的终止状态。
-
子进程的终止状态通过输出参数 status 返回给调用者,若不关心终止状态,可将此参数置空。
-
子进程的终止状态可借助 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;
}
-
如果同时存在多个子进程,又需要等待特定的子进程,可使用 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;
}
-
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);
- 标准 C 函数。执行 command,成功返回 command 对应进程的终止状态,失败返回 - 1。
- 若 command 取 NULL,返回非零表示 shell 可用,返回 0 表示 shell 不可用。
- 该函数的实现,调用了 fork、exec 和 waitpid 等函数,其返回值:
- 如果调用 fork 或 waitpid 函数出错,则返回 - 1。
- 如果调用 exec 函数出错,则在子进程中执行 exit (127)。
- 如果都成功,则返回 command 对应进程的终止状态 (由 waitpid 的 status 输出参数获得)。
- 用 system 函数而不用 fork+exec 的好处是,system 函数针对各种错误和信号都做了必要的处理。
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 - 进程管理 和用户管理
进程命令管理
进程:二进制加载到内存中,CPU执行期中指令整个过程
进程一定是运行中的程序PID 进程ID号
查看进程
ps :简略查看进程
top:动态查看进程
pstree:树状查看进程
[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}]
杀死进程
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显示后台任务
[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 &
用户管理
添加/删除用户
主组:默认下,每个用户默认创建的基本组
附加组:除了基本组外,用户可以属于的其他组
一个用户可以有很多组,但是主组只有一个.其余都是附加组
/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
一个运行的程序,可能有多个进程。
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 进程管理:
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是将新的程序的代码替换到该程序的代码空间中了。
两个函数的最后一个参数必须为0或NULL
函数的第一个参数是可执行程序的路径,第二个参数才是执行的命令
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等相关内容,可以在本站寻找。
本文标签: