进程

进程

进程标示

进程 ID -- 非负整数,唯一标示一个进程。 虽然是唯一,但可复用
系统中有一些专用进程。进程 ID 为 0 的进程通常是调度进程,常被称为交换进程(swapper) 也被成为系统进程。ID 为1 的通常是 init 进程。它是所有孤儿进程的父进程。

函数 fork

一个现有的进程可以调用 fork 函数创建一个新进程
由 fork 创建的新进程被称为子进程(child process) fork 函数调用一次,但返回2次。子进程返回的是0,父进程返回的是 子进程的 ID。子进程和父进程继续执行 fork调用之后的指令。

import os
import time
v = 80
pid = os.fork()
if pid == 0:
    v += 1
    print("child", v)
else:
    time.sleep(1)
    print("p>",v)
time.sleep(1)

一般来说 fork 之后子进程先执行还是父进程先执行是不确定的。

函数 wait waitpid

当一个进程正常退出或者异常终止时,内核就会向父进程 发送 SIGCHLD 信号。因为子进程终止是个异步事件。所以给父进程发的通知也是异步通知。父进程可以忽略此信号。或者提供一个该信号发生时即被调用的函数。对于这种信号的系统默认动作是忽略它。

  • 如果子进程都还在运行,则会阻塞。
  • 如果一个子进程终止,会取得该子进程的终止状态并立刻返回。
    如果它没有任务子进程则会出错返回。
import os
v = 80

pid = os.fork()

if pid == 0:
    print("child", v)
else:
    a  = os.wait()
    print(a)
    print("child has been finished")

返回值

('child', 80) # 恒先打印这个
(22365, 0)
child has been finished
('p>', 80)

wait 和 waitpid 函数的主要区别:

  • 在一个子进程终止前,wait 会使调用者阻塞。waitpid 有个选项可使调用者不会阻塞。
  • waitpid 并不等待其调用之后的第一个终止子进程。它有若干个选项,可以控制所等待的进程。
    如调用者阻塞且它有多个子进程,则在某某一子进程终止时,wait 就立即返回。因为 wait 返回终止子进程的进程 ID,所以他总能了解哪一个子进程终止了。

wait 出错的唯一原因是没有子进程

os.waitpid(pid, options)
对于参数pid,解释如下:
pid == -1 : 等待任一子进程,和 wait 等效
pid > 0 : 等待进程 id 与 pid 相同的 子进程
pid == 0 等待组 ID 等于调用进程组 ID 的任一子进程
pid < -1 等待组 ID 等于 pid 绝对值的任一子进程。

进程关系

进程组

每个进程除了有一个进程 ID 外,还属于一个进程组。通常他们是同一作业中结合起来的,同一进程组中的各进程接收来自同一终端的各种 信号。每个进程组有一个唯一的进程组 ID. 进程组 ID类似于进程 ID - 是一个正整数。函数 getpgrp 返回调用进程的进程组 ID。
每个进程组有一个组长进程。
每个进程组有一个组长进程,组长进程的进程组 ID等于其进程 ID
进程组的组长可以创建一个进程组,创建该组中的进程,然后终止。只要在某个进程组中有一个进程存在,那么这个进程组就存在。这与其组长进程是否终止无关。从进程组创建开始到其中最后一个进程离开为止的时间区间称为进程组的生命期。某个进程组中的最后一个进程可以终止,也可以转移到另一个进程组。

会话

会话是一个或多个进程组的集合。
进程调用 setsid 函数建立一个新的会话。
如果调用此函数的进程不是一个进程组的组长。那么次函数创建一个新的会话。具体如下

  1. 该进程编程新会话的会话首进程(session leader 会话首进程是创建该会话的进程) 。此时该进程是新会话的唯一进程。
  2. 该进程成为一个新进程组的组长进程。新进程组 ID 是该调用进程的 进程 ID。
  3. 该进程没有控制终端。如果在调用 setsid 之前该进程有一个控制终端,那这个联系也会被切断。
    如果调用此函数的进程已经是一个进程组的组长,则此函数返回出错。为了保证不处于这种情况,通常先调用 fork ,然后使其父进程终止,而子进程则继续。
    getsid 函数返回会话首进程的进程 ID

你可能感兴趣的:(进程)