进程
根据维基百科的定义,进程(Process)是计算机中已运行程序的实体。用户下达运行程序的命令后,就会产生进程。进程需要一些资源才能完成工作,如CPU使用时间、存储器、文件以及I/O设备,并且依序逐一进行.也就是每个CPU核心任何时间内仅能运行一项进程。
PID=1
有一个PID为1的进程是由内核创建的init进程,其他子进程都是由它衍生出来,进程号为1的进程并没有PPID
创建
操作系统通过POSIX定义的fork和exec接口创建起一个POSIX进程,这个进程就可以使用通用的IPC、信号等机制。
原来普通进程运行时默认会绑定TTY(虚拟终端),关闭终端后系统会给上面所有进程发送TERM信号,这时普通进程也就退出了。当然还有些进程不会退出,这就是后面将会提到的守护进程。
Nohup 的原理也很简单,终端关闭后会给此终端下的每一个进程发送SIGHUP信号,而使用nohup运行的进程则会忽略这个信号,因此终端关闭后进程也不会退出。
IPC全称Interprocess Communication,指进程间协作的各种方法,当然包括共享内存,信号量或Socket等。
FD
每个进程操作系统都会分配三个文件资源,分别是标准输入(STDIN)、标准输出(STDOUT)和错误输出(STDERR)。
Linux中“一切皆文件”,进程的一切运行信息(占用CPU、内存等)都可以在文件系统找到
go run
通过 go run 每次都会启动一个新的Go虚拟机来执行进程。
因为 go run 会启动进程重新编译、链接和运行程序,因此每次运行的进程名都不相同,而编译出来的程序有明确的名字,
进程锁
其实要实现一个进程锁很简单,通过文件就可以实现了。例如程序开始运行时去检查一个PID文件,如果文件存在就直接退出,如果文件不存在就创建一个,并把当前进程的PID写入文件中。
特殊的进程
- 孤儿进程
根据维基百科的解释,孤儿进程指的是在其父进程执行完成或被终止后仍继续运行的一类进程。
在现实中用户可能刻意使进程成为孤儿进程,这样就可以让它与父进程会话脱钩,成为后面会介绍的守护进程。
-
僵死进程
一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
进程间通信
-
管道(Pipe)
管道是进程间通信最简单的方式,任何进程的标准输出都可以作为其他进程的输入。
-
信号(Signal)
信号Signal,注意信号只是告诉进程发生了什么事件,而不会传递任何数据。
-
消息队列(Message)
和传统消息队列类似,但是在内核实现的。
-
共享内存(Shared Memory)
-
信号量(Semaphore)
信号量本质上是一个整型计数器,调用wait时计数减一,减到零开始阻塞进程,从而达到进程、线程间协作的作用。
-
套接口(Socket)
通过网络来通信,这也是最通用的IPC,不要求进程在同一台服务器上。
信号
进程发给进程,也可以是内核发给进程
kill -l
# HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2
其中1至31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),32到63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。
SIGINT 与字符ctrl+c关联,只能结束前台进程.
SIGTERM KILL命令的默认不带参数发送的信号就是
SIGTERM,可以被阻塞、处理和忽略.能让程序有好的退出。因为它可以被阻塞
SIGKILL
kill -9 进程号
触发.不可被阻塞、忽略.保证进程退出.
信号表
index | signal | desc |
---|---|---|
1 | SIGHUP | 本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联. |
2 | SIGINT | 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出 |
3 | SIGQUIT | 和SIGINT类似, 但由QUIT字符(通常是Ctrl-)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号. |
4 | SIGILL | 执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段.堆栈溢出时也有可能产生这个信号. |
5 | SIGTRAP | 由断点指令或其它trap指令产生. 由debugger使用. |
6 | SIGABRT | 程序自己发现错误并调用abort时产生. |
6 | SIGIOT | 在PDP-11上由iot指令产生, 在其它机器上和SIGABRT一样. |
7 | SIGBUS | 非法地址, 包括内存地址对齐(alignment)出错. eg: 访问一个四个字长的整数, 但其地址不是4的倍数. |
8 | SIGFPE | 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误. |
9 | SIGKILL | 用来立即结束程序的运行. 本信号不能被阻塞, 处理和忽略. |
10 | SIGUSR1 | 留给用户使用 |
11 | SIGSEGV | 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据. |
12 | SIGUSR2 | 留给用户使用 |
13 | SIGPIPE | Broken pipe |
14 | SIGALRM | 时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号. |
15 | SIGTERM | 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理. 通常用来要求程序自己正常退出. shell命令kill缺省产生这个信号. |
17 | SIGCHLD | 子进程结束时, 父进程会收到这个信号. |
18 | SIGCONT | 让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符 |
19 | SIGSTOP | 停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略. |
20 | SIGTSTP | 停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号 |
21 | SIGTTIN | 当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行. |
22 | SIGTTOU | 类似于SIGTTIN, 但在写终端(或修改终端模式)时收到. |
23 | SIGURG | 有”紧急”数据或out-of-band数据到达socket时产生. |
24 | SIGXCPU | 超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变 |
25 | SIGXFSZ | 超过文件大小资源限制. |
26 | SIGVTALRM | 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间. |
27 | SIGPROF | 类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间. |
28 | SIGWINCH | 窗口大小改变时发出. |
29 | SIGIO | 文件描述符准备就绪, 可以开始进行输入/输出操作. |
30 | SIGPWR | Power failure |