Linux常见进程类别
目录
常见进程类别
守护进程&精灵进程
任务管理
进程组
作业
作业 | 进程组
会话
w命令
守护进程
守护进程的创建
setsid()函数
daemon()函数
模拟实现daemon函数
前台进程 | 后台进程
僵尸进程 | 孤儿进程
僵尸进程的一些细节
守护进程 | 后台进程
守护进程 | 僵尸进程 | 孤儿进程
常见进程类别
- 僵尸进程:子进程先于父进程退出,父进程没有对子进程的退出进行处理,因此子进程会保存自己的退出信息而无法释放所有资源成为僵尸进程导致资源泄露。
- 孤儿进程:父进程先于子进程退出,子进程成为孤儿进程,运行在后台,父进程成为1号进程(而孤儿进程的退出,会被1号进程负责任的进行处理,因此不会成为僵尸进程)
- 守护进程&精灵进程:这两种是同一种进程的不同翻译,是特殊的孤儿进程,不但运行在后台,最主要的是脱离了与终端和登录会话的所有联系,也就是默默的运行在后台不想受到任何影响。
- 前台进程:前台的任务一启动,键盘输入的命令就是没有任何效果的,并且可以被CTRL c终止的进程。
- 后台进程:我们可以通过加一个&让前台进程变为在后台进行。当让其在后台进行时,命令是可以正常执行的,CTRL c是没有办法终止其的。
#:前台进程和后台进程在Linux系统中有着不同的意义和作用。
- 前台进程:是指当前正在运的程序所在的终端窗口处于活动状态,并且该程序正在终端窗口中输出信息或等待用户输入。此时,用户无法在该终端窗口中输入其他命令,直到该程序运行完毕或被用户手动停止。因此,前台进程通常用于需要用户交互的应用程序,例如编辑器、终端等。
- 后台进程:是指在后台运行的程序,它们不会占用当前终端窗口并且不会阻塞用户输入。用户可以在终端中同时执行多个命令,并且可以将一个正在运行的前台进程转为后台进程,使得该进程在后台继续执行而不影响用户操作。因此,后台进程通常用于需要长时间运行的任务或者需要在系统启动时自动运行的服务程序。
- ctr+z 将当前运行的程序放入后台挂起。
- jobs 命令,显示后台被挂起的所有进程。
- bg N 使第N个序号的任务在后台(background)运行。
- fg N 使第N个序号的任务在前台(foreground)运行。
守护进程&精灵进程
精灵进程&守护进程是一样的,不同的翻译叫法而已。
任务管理
进程组
在Linux系统中,每个进程都属于一个进程组。进程组是一组相关联的进程的集合,这些进程通常是由同一个父进程创建的,并且它们之间可以相互协作。每个进程组都有一个唯一的进程组ID(PGID),而每个进程也有一个唯一的进程ID(PID)。在同一个进程组中,其中一个进程会被指定为该组的领头进程(也称为“组长”),其PID等于PGID。只要在某个进程组中有一个进程存在,则该进程组就存在,这与其组长进程是否终止无关。
#:进程必定属于一个进程组,也只能属于一个进程组。
在Unix/Linux系统中,可以使用setpgid()系统调用将一个子进程添加到不同的进程组中。使用getpgrp()系统调用来获取当前进程所在进程组号。
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
- 返回值:
- 执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中。
- 参数:
- pid参数指定要设置的进程ID。
- 如果参数pid为0,则会用来设置目前进程的组识别码。
- pgid参数指定要设置的进程组ID。
- 如果参数pgid为0,则会以目前进程的进程识别码来取代。
- 如果pid和pgid相等,则该进程将成为一个新进程组的组长。
- pid参数指定要设置的进程ID。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main()
{pid_t id = fork();if (id == 0) {// 子进程printf("Child process: PID=%d, PGID=%d\n", getpid(), getpgrp());// 将子进程添加到新的进程组中setpgid(0, 0);printf("Child process after setpgid(): PID=%d, PGID=%d\n", getpid(), getpgrp());// 子进程执行一些任务sleep(10);exit(EXIT_SUCCESS);}else if(id > 0){// 父进程printf("Parent process: PID=%d, PGID=%d\n", getpid(), getpgrp());// 父进程执行一些任务sleep(5);exit(EXIT_SUCCESS);}else{perror("fork");exit(EXIT_FAILURE);}
}
子进程首先输出自己的PID和PGID,然后使用setpgid()函数将自己添加到一个新的进程组中,并再次输出自己的PID和PGID。父进程也输出自己的PID和PGID,并在子进程执行任务期间休眠5秒钟。运行该程序后,就可以看到子进程的PGID与父进程不同,即子进程已经成为一个新的进程组的组长。
[qcr@VM-16-6-centos test_2023_9_9]$ ./test
Parent process: PID=10606, PGID=10606
Child process: PID=10607, PGID=10606
Child process after setpgid(): PID=10607, PGID=10607
作业
作业指的是在终端或者控制台上运行的进程。当你在命令行输入一个命令并按下回车键后,这个命令就会以进程的方式在后台运行,并且会被分配一个唯一的作业号(job ID)。你可以使用job ID来管理和控制这个进程。在Linux中,有两种类型的作业:前台作业和后台作业。前台作业是指当前正在终端或者控制台上运行的进程,而后台作业则是指在后台运行的进程。
作业控制控制前后台进程的步骤:
1、启动一个进程并将其放到后台运行
在命令行终端上启动一个命令时,在该命令末尾加上 '&' 符号即可将其放到后台运行。例如:$ long_running_command &
2、查看当前正在运行的作业
可以使用 'jobs' 命令查看当前正在运行的作业及其状态。例如:$ jobs [1]+ Running long_running_command &
3、将后台进程调回前台
可以使用 'fg' 命令将一个后台进程调回前台。例如:$ fg n
4、将前台进程放到后台
可以使用 'Ctrl+Z' 键将当前前台进程暂停,并将其放到后台运行,但使用Ctrl+Z后该进程就会处于停止状态(Stopped)。例如:^Z [1]+ Stopped long_running_command
5、恢复被暂停的后台进程
可以使用 'bg' 命令将被暂停的后台进程恢复运行。例如:$ bg n [1]+ long_running_command &
6、终止进程
可以使用 'Ctrl+C' 键向前台进程发送 'SIGINT' 信号,终止该进程的运行。如果想要强制终止一个进程,可以使用 'kill' 命令。例如:$ kill -9 <pid>
作业 | 进程组
- 进程组:是一个进程 / 具有相同进程组ID的一组进程,它们之间没有必然的关联,但是可以通过进程组ID方便地对它们进行管理。
#:融会贯通的理解
假设要完成一个任务,需要同时并发100个进程。当用户处于某种原因要终止这个任务时,要是没有进程组,就需要手动的一个个去杀死这100个进程,并且必须要严格按照进程间父子兄弟关系顺序,否则会扰乱进程树。有了进程组,就可以将这100个进程设置为一个进程组,它们共有1个组号(pgrp),并且有选取一个进程作为组长(通常是“辈分”最高的那个,通常该进程的ID也就作为进程组的ID)。现在就可以通过杀死整个进程组,来关闭这100个进程,并且是严格有序的。组长进程可以创建一个进程组,创建该组中的进程,然后终止。(来源:Linux-进程、进程组、作业、会话、控制终端详解 - John_ABC)
- 作业:是一个进程 / 具有关联联系的多个进程,这些进程通常由同一个父进程创建,并且它们共享同一个终端。
#:融会贯通的理解
在Linux中,一个进程可以通过管道(pipe)、作业控制(job control)、信号(signal)等方式与其他进程进行直接关联。
因此,尽管作业和进程组都是由多个程序或任务组成的集合,但它们之间有所不同。作业更加高级,包含更多元素(如文件、输入输出等),而进程组则更注重管理和控制多个相关联的进程。
#:都是操作系统中的概念,用于方便对一组相关联的进程进行管理和控制。
作业与进程组的区别:如果作业中的某个进程又创建了子进程,则子进程不属于作业。一旦作业运行结束,Shell就把自己提到前台,如果原来的前台进程还存在(如果这个子进程还没终止),它自动变为后台进程组。父进程创建的子进程默认情况下属于同一进程组。在Unix/Linux系统中,每个进程都有一个唯一的进程ID(PID)和一个进程组ID(PGID)。当父进程创建子进程时,子进程会继承父进程的PGID,因此它们属于同一进程组。
会话
由于Linux是多用户多任务的分时系统,所以必须要支持多个用户同时使用一个操作系统。当一个用户登录一次系统就形成一次会话 。一个会话可包含多个进程组,但只能有一个前台进程组。每个会话都有一个会话首领(leader),即创建会话的进程。
一个用户可以在同一时间拥有多个会话。在Linux系统中,每个用户都可以通过终端、SSH等方式登录到系统中,并启动一个新的会话。这些会话可以同时运行不同的进程和任务,且互相独立,互不干扰。每个会话都有一个唯一的ID号,称为Session ID(SID),用于区分不同的会话。而每个进程也有一个唯一的Process ID(PID),用于区分不同的进程。通过命令 "who" 或者 "w" 可以查看当前登录系统的用户和他们所拥有的会话。
w命令
w命令实际上用于显示当前终端的前台进程,而一个会话只能有一个前台进程。因此,通过观察w命令的输出,所以可以间接推断出当前系统中有多少个会话。
(此处有一个会话执行w命令,所以w对应的进程变为了前台进程,bash变为了后台进程)
w命令的属性字段:
USER : 登录用户的用户名。
TTY : 登录用户所使用的终端设备。
FROM : 登录用户的IP地址或远程主机名。
LOGIN@ : 登录时间,格式为月日时分。
IDLE : 用户空闲时间,即从上次输入开始到现在的时间。
JCPU : 所有进程占用CPU时间的总和,单位为分钟。
PCPU : 当前进程占用CPU时间百分比。
WHAT : 当前登录用户所执行的命令或进程。
参数说明:
-f 开启或关闭显示用户从何处登入系统。
-h 不显示各栏位的标题信息列。
-l 使用详细格式列表,此为预设值。
-s 使用简洁格式列表,不显示用户登入时间,终端机阶段作业和程序所耗费的CPU时间。
-u 忽略执行程序的名称,以及该程序耗费CPU时间的信息。
-V 显示版本信息。
#:融会贯通的理解
一个会话可以有一个控制终端。这通常是登陆到其上的终端设备(在终端登陆情况下)或伪终端设备(在网络登陆情况下)。建立与控制终端连接的会话首进程被称为控制进程。一个会话中的几个进程组可被分为一个前台进程组以及一个或多个后台进程组。所以一个会话中,应该包括控制进程(会话首进程),一个前台进程组和任意后台进程组。
在Linux/Unix系统中,当我们启动一个新的shell时,通常情况下会先由init进程启动一个getty或login进程,当我们在终端输入用户名和密码后,getty或login进程会验证用户身份,并为该用户创建一个新的会话(session)和控制终端(controlling terminal)。然后,该进程会使用exec函数族调用启动一个新的shell程序(如bash),并将其加入到该会话的前台进程组中。此时,init进程成为了该会话的控制进程,而bash进程则成为了该会话的前台进程。#:前台进程只能有一个,当一个进程变成前台进程后,bash会自动变为后台进程,此时bash就无法进行命令行解释了。
setsid()调用能创建一个会话。必须注意的是,只有当前进程不是进程组的组长时,才能创建一个新的会话。调用setsid 之后,该进程成为新会话的leader。
#include <unistd.h>pid_t setsid(void);
使用 'setsid' 函数可以将一个进程从其父进程所在的终端分离出来,使其成为一个独立的后台进程,并且不再受到终端关闭等事件的影响。
- 创建一个子进程(fork)。
- 在子进程中调用 'setsid' 函数创建一个新会话。
- 关闭子进程中不需要的文件描述符(close)。
- 更改当前工作目录(chdir)。
- 重定向标准输入、输出、错误输出到/dev/null或其他文件(dup2)。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{pid_t pid;// 创建子进程pid = fork();if(pid == -1){perror("fork");exit(EXIT_FAILURE);}else if(pid > 0){// 父进程退出exit(EXIT_SUCCESS);}// 在子进程中创建新会话if(setsid() == -1){perror("setsid");exit(EXIT_FAILURE);}// 关闭不需要的文件描述符close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);// 更改当前工作目录chdir("/");// 重定向标准输入、输出、错误输出到/dev/nullint fd = open("/dev/null", O_RDWR, 0);dup2(fd, STDIN_FILENO);dup2(fd, STDOUT_FILENO);dup2(fd, STDERR_FILENO);while(1){// 后台进程逻辑代码sleep(1);}return 0;
}
该程序在执行时,会创建一个后台进程,并将其从终端分离出来。后台进程的逻辑代码可以在while循环中实现,此处只是简单地使用sleep函数模拟了一下。
守护进程
#:守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程(一种长期运行的后台进程),它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件,如监控硬件设备、网络服务等。
特点:
- 通常是由系统管理员启动的,而不是由用户手动启动。
- 通常不与终端关联,因此没有标准输入、输出和错误输出。
- 通常需要以root权限运行,以便访问系统资源。
- 通常会定期检查某些事件或条件,并根据需要采取相应的操作。
- 通常会将自己作为后台进程运行,并将自己从父进程中分离出来。
- 通常会将文件描述符重定向到/dev/null或其他日志文件中,以避免产生不必要的输出信息。
凡是TPGID一栏写着-1的都是没有控制终端的进程,也就是守护进程。
在COMMAND一列用 [ ] 括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用以k开头的名字,表示Kernel
守护进程的创建
setsid()函数
setsid()调用能创建一个会话。必须注意的是,只有当前进程不是进程组的组长时,才能创建一个新的会话。调用setsid 之后,该进程成为新会话的leader。
#include <unistd.h>pid_t setsid(void);
- 返回值
- 如果调用成功,返回新的会话ID。
- 如果调用失败,返回 -1 并设置errno变量。
- 在父进程中调用fork(),然后使父进程exit(),这样可以让子进程继承父进程的会话(session)和进程组(process group)。
- 在子进程中调用setsid()函数,建立一个新的会话(session),使子进程成为该新会话的领头进程(leader process),同时也成为一个新的进程组(group)的领头进程,从而与原来的控制终端分离。如果setsid返回-1,则表示出错。
- 为了防止在某个时刻重新获得控制终端,需要再次fork()一次,并使父进程exit()。这样保证了守护进程不会重新获得控制终端。
- 在守护进程中修改工作目录(chdir())和文件屏蔽字(umask())等环境变量,以便更好地适应后台运行环境。
- 守护进程不能直接和用户交互,也就是说守护进程已经与终端去关联了,因此一般我们会将守护进程的标准输入、标准输出以及标准错误都重定向到
/dev/null
,/dev/null
是一个字符文件(设备),通常用于屏蔽/丢弃输入输出信息。 - 正式执行守护进程任务代码。
- 在程序结束时释放资源并退出。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{// 创建子进程pid_t pid = fork();// 如果创建子进程失败,则直接退出if(pid == -1){perror("fork");exit(1);}// 如果是父进程,则直接退出if(pid > 0){exit(0);}// 在子进程中创建新会话,并成为领头进程if(setsid() == -1){perror("setsid");exit(1);}// 第二次fork,创建孙子进程pid = fork();// 如果创建孙子进程失败,则直接退出if(pid == -1){perror("fork");exit(1);}// 如果是父进程,则直接退出if(pid > 0){exit(0);}// 将标准输入、标准输出、标准错误重定向到/dev/nullclose(0);int fd = open("/dev/null", O_RDWR);dup2(fd, 1);dup2(fd, 2);// 修改工作目录和文件屏蔽字chdir("/");umask(0);// 正式执行守护进程任务代码while(1){// do something...sleep(10);}return 0;
}
第二次fork()主要是为了避免守护进程在未来可能会因为某些原因重新获得控制终端而导致进程退出的问题。
#:融汇贯通的理解
具体来说,会有个SIGHUP信号,其是一种由操作系统发送给进程的信号,通常表示 “终端挂起” 。在Linux操作系统中,当一个进程打开了一个终端设备(例如控制台窗口),并且该终端设备被关闭或者与该进程失去联系时,操作系统会向该进程发送SIGHUP信号。
在守护进程中,如果只进行一次fork()操作,则该子进程仍然会与原来的控制终端相关联。如果此时用户关闭了控制终端,则操作系统会向该子进程发送SIGHUP信号。如果程序没有处理这个信号,则可能会导致程序异常退出。
因此,需要进行第二次fork()操作。这样,在第二次fork()之后,会产生一个孙子进程,并使孙子进程成为真正的守护进程。而孙子进程与其父进程和原来的控制终端、信号等都已经完全脱离关系。
[qcr@VM-16-6-centos test_2023_9_10]$ ps axj | head -1 && ps axj | grep testPPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 4382 4381 4381 ? -1 S 1001 0:00 ./test9217 4483 4482 9160 pts/0 4482 S+ 1001 0:00 grep --color=auto test
运行代码,用ps命令查看该进程,会发现该进程的TPGID为-1,TTY显示的是 ?,也就意味着该进程已经与终端去关联了。
进程的SID与bash进程的SID是不同的,即它们不属于同一个会话。
- 通过
ls /proc/进程id -al
命令,可以看到该进程的工作目录已经成功改为了根目录。 - 通过
ls /proc/进程id/fd -al
命令,可以看到该进程的标准输入、标准输出以及标准错误也成功重定向到了/dev/null
。
/proc
在Linux系统中,/proc是一个虚拟文件系统,它提供了对系统内核和进程的信息的访问。/proc目录下包含了很多文件和子目录,每个文件或子目录都代表着一个进程或系统内核的一些信息。
/proc/cpuinfo : 包含了CPU的信息。 /proc/meminfo : 包含了内存的信息。 /proc/net : 包含了网络相关的信息。 /proc/sys : 包含了一些内核参数和系统配置信息。 /proc/<pid> : 代表着一个进程,其中pid是进程的ID号。该目录下包含了该进程的很多信息,如进程状态、打开的文件、内存映射、线程等。
daemon()函数
在Unix/Linux系统中,我们可以使用daemon()函数来创建Daemon进程。
#include <unistd.h> int daemon(int nochdir, int noclose);
- 参数
- nochdir:如果该参数为0,则在调用daemon()函数后,进程的当前工作目录会被设置为根目录 "/" ;如果该参数不为0,则进程的当前工作目录不会改变。
- noclose:如果该参数为0,则在调用daemon()函数后,进标准输入、标准输出以及标准错误重定向到
/dev/null
;如果该参数不为0,则进程不会关闭任何文件描述符。- 返回值
- 0表示成功。
- 返回-1表示失败,并设置errno变量。
#include <unistd.h>int main()
{daemon(0, 0);while (1);return 0;
}
调用daemon函数创建的守护进程与setsit函数创建的守护进程差距不大,唯一区别就是daemon函数创建出来的守护进程,既是组长进程也是会话首进程。也就是说系统实现的daemon函数没有防止守护进程打开终端,因此我们实现的反而比系统更加完善。
模拟实现daemon函数
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>int my_daemon(int nochdir, int noclose)
{pid_t pid;// 创建子进程pid = fork();if (pid == -1) {perror("fork error");exit(EXIT_FAILURE);} else if (pid > 0) {// 父进程退出exit(EXIT_SUCCESS);}// 子进程调用setsid()函数创建新会话,并成为会话组长和进程组长if (setsid() == -1) {perror("setsid error");exit(EXIT_FAILURE);}// 忽略SIGHUP信号signal(SIGHUP, SIG_IGN);// 再次创建子进程,退出父进程,保证守护进程不是会话组长和进程组长pid = fork();if (pid == -1) {perror("fork error");exit(EXIT_FAILURE);} else if (pid > 0) {// 父进程退出exit(EXIT_SUCCESS);}// 如果nochdir参数为0,则将当前工作目录更改为根目录if (nochdir == 0) {chdir("/");}// 将标准输入、标准输出、标准错误重定向到/dev/nullif (noclose == 0){close(0);int fd = open("/dev/null", O_RDWR);dup2(fd, 1);dup2(fd, 2);}// 设置umask为0,以便守护进程可以创建任意权限的文件umask(0);return 0;
}
my_daemon()函数首先通过调用 'fork()' 函数创建了一个子进程。然后,在父进程中直接退出,而在子进程中调用 'setsid()' 函数创建新会话,并成为会话组长和进程组长。接着,忽略SIGHUP信号,并再次创建子进程,退出父进程,保证守护进程不是会话组长和进程组长。最后,根据传入的参数设置工作目录、关闭标准输入输出和标准错误输出、以及设置umask。
前台进程 | 后台进程
#:前台进程和后台进程是两个不同的概念!
- 前台进程是指正在与用户交互的进程,通常会占用屏幕显示资源,需要用户进行操作才能继续运行。而后台进程则是在后台默默运行的进程,用户通常无法直接看到或者进行交互。
- 前台进程通常是用户启动的应用程序或者系统服务,如浏览器、文本编辑器等,而后台进程通常是由系统自动启动或者其他程序调用的服务程序。
- 前台进程通常需要占用大量资源才能正常运行,如CPU、内存等;而后台进程则通常不需要太多资源,但是需要长时间稳定地运行。
- 前台进程,用户可以通过界面操作来控制其运行状态;而后台进程,则需要通过命令行工具或者其他管理工具来进行控制和管理。
僵尸进程 | 孤儿进程
#:孤儿进程和僵尸进程是两个不同的概念!
- 孤儿进程是指其父进程已经退出或者异常终止,但是该进程仍然在运行的进程。这种情况通常发生在父进程意外退出或者没有正确处理子进程退出状态的情况下。而僵尸进程则是指已经完成执行任务,但是其父进程还没有来得及处理它们的退出状态信息的进程。
- 孤儿进程会被init进程(PID为1)接管,并成为init的子进程,由init负责回收它们的资源。而僵尸进程则需要被及时清理以释放系统资源。
- 孤儿进程占用系统资源,如果大量存在则可能导致系统性能下降。而僵尸进程不会占用太多系统资源,但是如果存在过多则可能导致系统性能下降。
- 孤儿进程需要被接管并继续运行或者被正确处理,而僵尸进程则需要被及时清理以释放系统资源。
- 孤儿进程是一个正在运行的进程,僵尸进程是一个已死的进程。
僵尸进程的一些细节
僵尸进程已经死亡,因此无法使用kill命令杀死它们。实际上,僵尸进程的退出状态信息已经被内核保存了下来,但是其父进程没有及时处理这些信息,导致僵尸进程一直处于“僵死”状态。要彻底清除僵尸进程,需要通过其父进程将其退出状态信息处理完毕,并调用wait或waitpid函数来回收其资源。
#:僵尸进程父进程又没有回收?
父进程正执行:
如果僵尸进程的父进程一直没有回收它,那么这个僵尸进程所占用的资源(如内存、文件描述符等)将一直被占用,直到系统重启或者其他操作将其释放。长时间存在大量僵尸进程会浪费系统资源,降低系统性能。
解决方案:
可以通过手动杀死父进程来强制回收所有僵尸进程的资源(正是下一种方法)。但是这种操作需要谨慎处理,因为杀死父进程可能会影响其他正在运行的进程。更好的方法是通过修改程序代码,在父进程中添加对子进程退出状态信息的处理代码,及时回收子进程的资源。
父进程已死亡:
#:并不是网上有些说的会变为孤儿进程。
此时,子进程的父进程ID会被设置为1,也就是init进程的ID。然后init进程会定期轮询检查是否有僵尸进程需要处理,并回收它们的资源。
因此,终止父进程后僵尸进程并不会转变为孤儿进程交给init处理,而是由init负责回收其资源。
守护进程 | 后台进程
#:后台进程和守护进程是两个不同的概念!可以看作守护进程是特殊的后台进程。
后台进程是指运行在后台的进程,它们不会占用当前终端窗口并且不需要用户输入,而是在后台默默地执行。用户可以使用特定的命令将一个前台进程转化为后台进程,或者直接启动一个后台进程。而守护进程则是一种特殊的后台进程,它通常是由系统启动时自动启动的,并且会一直运行,直到系统关闭。它们通常不受用户交互影响,并且会在后台执行某些系统任务或服务。例如,网络服务(如Web服务器、FTP服务器等)就是通过守护进程来实现的。
后台进程相比守护进程特点:
- 守护进程通常会从父进程中脱离出来,成为一个独立的进程组和会话,并且会重新设置文件权限等环境变量。
- 守护进程通常会定期检查和处理一些任务,以保证其正常运行。例如,Web服务器会定期清理日志文件、更新缓存等操作。
- 守护进程通常会记录日志信息,并将其写入到指定的日志文件中,以便于管理员进行故障排查和问题定位。
总之,后台进程和守护进程都是Linux系统中常见的进程类型,但守护进程通常会比普通的后台进程更加复杂和功能强大。
守护进程 | 僵尸进程 | 孤儿进程
精灵进程&守护进程是一样的,不同的翻译叫法而已,它的父进程是1号进程,退出后不会成为僵尸进程、孤儿进程。
#:init进程
init进程是Linux系统中的第一个进程,其进程号始终为1。在Linux系统启动时,内核会首先启动init进程,并由它来启动其他所有进程。init进程主要负责初始化系统环境、启动各种服务和守护进程,并监控这些进程的运行状态。如果某个进程异常退出或崩溃,init进程会尝试重新启动该进程,以确保系统稳定运行。
相关文章:
Linux常见进程类别
目录 常见进程类别 守护进程&精灵进程 任务管理 进程组 作业 作业 | 进程组 会话 w命令 守护进程 守护进程的创建 setsid()函数 daemon()函数 模拟实现daemon函数 前台进程 | 后台进程 僵尸进程 | 孤儿进程 僵尸进程的一些细节 守护进程 | 后台进程 守护…...
智能小车之蓝牙控制并测速小车、wife控制小车、4g控制小车、语音控制小车
目录 1. 蓝牙控制小车 2. 蓝牙控制并测速小车 3. wifi控制测速小车 4. 4g控制小车 5. 语音控制小车 1. 蓝牙控制小车 使用蓝牙模块,串口透传蓝牙模块,又叫做蓝牙串口模块 串口透传技术: 透传即透明传送,是指在数据的传输过…...
指针进阶(一)
指针进阶 1. 字符指针面试题 2. 指针数组3. 数组指针3.1 数组指针的定义3.2 &数组名VS数组名 3.3 数组指针的使用4. 数组传参和指针传参4.1 一维数组传参4.2 二维数组传参4.3 一级指针传参4.4 二级指针传参 前言 指针的主题,我们在初级阶段的《指针》章节已经接…...
c# sql 判断表中是否包含指定字段
你可以使用以下方法来判断一个 SQL 数据库中的表是否包含指定的字段。 首先,你需要连接到数据库,然后执行一条 SQL 查询语句来检查表结构。你可以使用 SELECT 语句和 INFORMATION_SCHEMA.COLUMNS 系统视图来获取表中的所有列信息。 下面是一个示例代码…...
08-JVM垃圾收集器详解
上一篇:07-垃圾收集算法详解 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。 虽然我们对各个收集器进行比较,但并非为了挑选出一个最好的收集器。因为直到现在为止还没有最好的垃圾收集器出现,更加没…...
sql_mode详解
文章目录 一、sql_mode作用二、查询sql_mode三、mysql8默认的mode配置(6个默认配置)四、常见mode详细解释mysql8默认配置了的mode(6个)需要自己配置的mode(4个) 五、设置sql_mode(一旦设置了&am…...
Vue3的新特性总结
一、Vue3 里 script 的三种写法 首先,Vue3 新增了一个叫做组合式 api 的东西,英文名叫 Composition API。因此 Vue3 的 script 现在支持三种写法。 1、最基本的 Vue2 写法 <template><div>{{ count }}</div><button click"…...
【Node】Mac多版本Node切换
1、查看当前电脑是否安装node node -v或者查看当前电脑通过brew安装的node路径 ls /usr/local/Cellar/node*2、查看可安装的node brew search node3、安装其他版本node 下载需要安装的node版本 brew install node144、brew切换node版本 假设之前的版本是18,需…...
Apache POI
POI介绍 Apache POI是用Java编写的免费开源的跨平台的Java API, Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能, 其中使用最多的就是使用POI操作Excel文件。 maven坐标: <dependency><groupId>org.apa…...
个人能做股票期权吗?个人期权交易开户条件新规
个人投资者是可以交易股票期权的,不过期权交易通常需要投资者具备一定的投资经验和风险承受能力,因为期权交易涉及较高的风险和复杂性,下文为大家介绍个人能做股票期权吗?个人期权交易开户条件新规的内容。本文来自:期…...
Java面试整理(一)
开篇 面试,应该都是打工人需要面对的事情。我记得自己以前开始准备Java工程师面试时,都会去看那个《面试宝典》,当时这个“宝典”真的很经典,现在应该还是不少朋友会看这个。我自己经历过了找工作的面试,和企业招聘工作。所以我自己更加想从这两个不同的角度去和大家交流这…...
国家信息中心举办“数字政府建设暨数字安全技术”研讨会:海云安提出数字政府软件供应链安全解决方案
近日,由国家信息中心主办,复旦大学研究院承办的“数字政府建设暨数字安全技术研讨会”在义乌顺利召开。国家信息中心信息与网络安全部副主任禄凯,复旦大学党委常委、宣传部部长陈玉刚,义乌市委常委、常务副市长喻新贵为会议致辞。…...
uniapp 处理 分页请求
我的需求是手机上一个动态滚动列表,下拉到底部时,触发分页数据请求 uniapp上处理分页解决方案 主要看你是如何写出滚动条的。我想到的目前有三种 (1)页面滚动:直接使用onReachBottom方法,可以监听到达底部…...
最新2米分辨率北极开源DEM数据集(矢量文件)
一、项目背景 美国明尼苏达大学(University of Minnesota)的极地地理空间中心(Polar Geospatial Center, PGC)于2023年8月发布了北极数字高程模型4.1版本(ArcticDEM Mosaic 4.1)。该DEM数据集是革命性的,分辨率达到了2米,而一般的开源DEM数据集分辨率是3…...
【计算机网络】HTTP(下)
本文承接上文的代码进行改造,上文链接:HTTP上 文章目录 1. 实现网站跳转实现 自己的网站跳转 2. 请求方法(get) && 响应方法(post)GET方法POST方法GET与POST的应用场景 3. HTTP状态码在自己设计的代码中发现4043开头的状态码(重定向状态码)永久…...
自学Python03-学会Python中的while循环语句
我们来学习一下怎么使用列表和字典吧! 1.列表 首先,我们来学习一下列表。列表是一个有序的集合,它可以包含任何类型的数据,比如数字、字符串或其他列表。我们可以用方括号 [] 来创建一个列表,用逗号分隔各个元素。 …...
PatchMatchNet 学习笔记 译文 深度学习三维重建
9 PatchMatchNet CVPR-2021 patchmatchnet源码下载 PatchMatchNet 代码注释版 下载链接(注释非常详细,较源码结构有调整,使用起来更方便) PatchMatchNet-CVPR-2021(源码、原文+注释+译文+批注) 9.0 主要特点 金字塔,基于传统的PatchMatch算法,精度高,速度快 Pa…...
为什么要使用设计模式,以及使用设计模式的好处
在软件开发中,衡量软件质量只要包含如下指标: 正确性可维护性可读性可扩展性简洁性可测试性健壮性灵活性可复用性 然而,对于一些刚入行的新程序员来说,往往会注意不到上面这些问题,从而产生了一些让人头皮发麻的烂代…...
【Springcloud】Sentinel熔断和降级
【Springcloud】Sentinel熔断和降级 【一】基本介绍【1】什么是熔断和降级【2】为什么使用熔断和降级【3】Sentinel熔断和降级【4】核心概念 【二】下载方式【1】Windows平台安装包下载【2】打开控制台 【三】使用案例【1】添加依赖【2】添加Sentinel配置【3】添加TestUserCont…...
javascript实战开发:json数据求指定元素的和算法
项目需求 在js中,格式如: [{"name": "一(0)班-电量,一(9)班-电流,一(9)班-功率","odata": {"prev_0_day_val_diff": "10.189941,-3.0,79.0",} },{"name": "一(10)班-电量,一(10)班-…...
娱乐时间 —— 用python将图片转为excel十字绘
最近看蛮多朋友在玩,要么只能画比较简单的,要么非常花时间。想了下本质上就是把excel对应的单元格涂色,如果能知道哪些格子要上什么颜色,用编程来实现图片转为excel十字绘应该是很方便的。 图片的每一个像素点都可以数值化&#x…...
OJ练习第160题——LRU 缓存
LRU 缓存 力扣链接:146. LRU 缓存 题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓…...
使用 Hugging Face Transformer 创建 BERT 嵌入
介绍 最初是为了将文本从一种语言更改为另一种语言而创建的。BERT 极大地影响了我们学习和使用人类语言的方式。它改进了原始 Transformer 模型中理解文本的部分。创建 BERT 嵌入尤其擅长抓取具有复杂含义的句子。它通过检查整个句子并理解单词如何连接来做到这一点。Hugging F…...
unity 控制Dropdown的Arrow箭头变化
Dropdown打开下拉菜单会以“Template”为模板创建一个Dropdown List,在“Template”上添加一个脚本在Start()中执行下拉框打开时的操作,在OnDestroy()中执行下拉框收起时的操作即可。 效果代码如下用于控制Arrow旋转可以根据自己的想法进行修改ÿ…...
Java开发面试--nacos专区
1、 Nacos是什么? 请简要介绍Nacos是什么以及它的主要功能和用途。 答: 简介: Nacos是一个开源的、高性能、动态服务发现、配置和服务管理平台,通常用于微服务架构中。Nacos的名称来源于"Naming"(服务发现…...
GB28181学习(三)——心跳保活
心跳保活 要求: 1. 当原设备发现工作异常时,应立即向本SIP监控域的SIP服务器发送状态信息; 2. 无异常时,定时向本SIP监控域的SIP服务器发送状态信息; 3. 状态信息报送采用**MESSGAE**方法; 4. SIP设备宜在…...
黑马JVM总结(三)
(1)栈内存溢出 方法的递归调用,没有设置正确的结束条件,栈会有用完的一天,导致栈内存溢出 可以修改栈的大小: 再次运行:减少了次数 案例二: 两个类的循环应用问题,导致Js…...
【数据结构】二叉树基础入门
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
MFC自定义消息的实现方法----(线程向主对话框发送消息)、MFC不能用UpdateData的解决方法
在MFC中,我们一边在使用多线程时,经常会遇到在需要调用到新建的控件,此时建议不要在新建的线程中直接调用主对话框的控件,我们可以通过自定义消息,在新建线程中发送并触发主线程进行相关的界面控件操作。 以Dialog对话…...
Linux单列模式实现线程池
目录 一、单列模式 1.1 单列模式概念以及实现条件 1.2 饿汉模式 1.1.1 饿汉模式代码实现 1.1.2 饿汉模式特征和优缺点 1.3 懒汉模式 1.3.1 懒汉模式代码实现 1.3.2 懒汉模式特征以及优缺点 二、线程池 2.1 线程池概念 2.2 实现简单线程池逻辑 2.3 模拟实现懒汉模式线程…...
百年建筑网站/seoyoon
UVA 11077 - Find the Permutations 题目链接 题意:给定n,k求出有多少个包括元素[1-n]的序列,交换k次能得到一个[1,2,3...n]的序列 思路:递推dp[i][j]表示i个元素须要j次。那么在新加一个元素的时候。添在最后面次数不变。其余位置都是次数1&…...
嘉兴网站推广优化/每日英语新闻
一、原因: pip由于默认使用国外源,有时候会被墙,导致出现 Read timed out 二、更换国内镜像源 (1)临时使用 pip install module_name -i https://pypi.douban.com/simple (2)全局使用 - L…...
西宁市企业建站专业/免费h5制作网站
尽管很多 NoSQL 数据库近几年大放异彩,但是像 MySQL 这样的关系型数据库依然是互联网的主流数据库之一,每个学 Python 的都有必要学好一门数据库,不管你是做数据分析,还是网络爬虫,Web 开发、亦或是机器学习࿰…...
一家做特卖的网站叫什么时候/刚刚北京传来重大消息
案例介绍 张三是公司 COMP 中的一名测试工程师,他所在的部门是位于北京的测试部 DEPTA 。 COMP 的邮件系统和应用程序系统均采用 Notes/Domino,无论是收发邮件还是访问报销系统、休假系统等均需要使用 Notes ID 通过 Notes Client 来进行。 COMP 的 Doma…...
类似wordpress的博客/高端企业网站建设
1 DevOps的意图究竟什么是DevOps? 要想回答这个问题,首先要明确DevOps这个过程参与的人员是谁?即开发团队和IT运维团队!那么,DevOps的意图是什么呢?即在两个团队之间,建立良好的沟通和协作,更快…...
手机网站网站开发流程/网站建设服务公司
铝合金车架、前后100mm避震行程、超短把立、长款燕把、27.5轮径……之前跟大家讲过,在这台车上你能拥有全避震车型所应该具备的所有基础元素。2个月的时间已经过去,这台车到底怎么样呢?我们一起来看一下。优点:质量靠谱࿰…...