ZetCode

Python os.getpgid 函数

上次修改时间:2025 年 4 月 11 日

本综合指南探讨了 Python 的 os.getpgid 函数,该函数检索进程组 ID。我们将介绍 Unix 进程组、实际用法示例以及相关的进程管理函数。

基本定义

os.getpgid 函数返回具有指定进程 ID (pid) 的进程的进程组 ID。进程组是用于作业控制和信号分配的 Unix 构造。

关键参数:pid(要查询的进程 ID,0 表示当前进程)。将进程组 ID 作为整数返回。对于无效 pid,引发 ProcessLookupError。

获取当前进程组 ID

os.getpgid 最简单的用法是通过传递 0 作为 pid 参数来检索当前进程的组 ID。 这通常用作参考。

current_pgid.py
import os

# Get current process group ID
current_pgid = os.getpgid(0)
print(f"Current process group ID: {current_pgid}")

# Compare with os.getpgrp()
assert current_pgid == os.getpgrp()
print("os.getpgid(0) matches os.getpgrp()")

此示例展示了如何获取当前进程组 ID。它还演示了 os.getpgid(0) 等同于 os.getpgrp()。

进程组 ID 通常与组领导者(组中的第一个进程)的进程 ID 相同。

获取子进程组 ID

创建子进程时,可以检查其进程组 ID。此示例 fork 一个子进程并检查其组 ID。

child_pgid.py
import os
import time

# Create a child process
pid = os.fork()

if pid == 0:  # Child process
    child_pgid = os.getpgid(0)
    print(f"Child process group ID: {child_pgid}")
    time.sleep(1)
else:  # Parent process
    parent_pgid = os.getpgid(0)
    child_pgid = os.getpgid(pid)
    print(f"Parent process group ID: {parent_pgid}")
    print(f"Child's process group ID: {child_pgid}")
    os.waitpid(pid, 0)

父进程检索其自身和子进程的进程组 ID。 默认情况下,子进程继承父进程的进程组。

这演示了进程组通常是如何继承的,除非使用 os.setpgid() 显式更改。

更改进程组

此示例展示了如何创建新的进程组并使用 os.getpgid 验证更改。

new_pgroup.py
import os

# Create a child process
pid = os.fork()

if pid == 0:  # Child process
    # Create new process group
    os.setpgid(0, 0)
    new_pgid = os.getpgid(0)
    print(f"New process group ID: {new_pgid}")
else:  # Parent process
    # Wait for child to change group
    os.waitpid(pid, 0)
    # Verify child's new group
    child_pgid = os.getpgid(pid)
    print(f"Child's new group ID: {child_pgid}")
    assert child_pgid == pid  # New group ID is child's PID

子进程创建一个新的进程组,并以自身作为领导者。父进程验证子进程的新组 ID 是否与其进程 ID 匹配。

当 shells 为命令管道创建新的作业控制组时,通常会这样做。

处理无效进程 ID

当给定无效进程 ID 时,os.getpgid 引发 ProcessLookupError。此示例演示了正确的错误处理。

invalid_pid.py
import os

def safe_getpgid(pid):
    try:
        pgid = os.getpgid(pid)
        print(f"Process {pid} belongs to group {pgid}")
        return pgid
    except ProcessLookupError:
        print(f"Process {pid} does not exist")
        return None

# Test with valid and invalid PIDs
safe_getpgid(0)  # Current process
safe_getpgid(999999)  # Non-existent process

safe_getpgid 函数通过捕获 ProcessLookupError 来优雅地处理无效进程 ID。 这可以防止在查询任意进程时发生崩溃。

在处理进程管理函数时,始终验证进程 ID 或处理异常。

比较进程组

此示例演示了比较进程组 ID 以确定进程是否属于同一组。

compare_groups.py
import os

def are_in_same_group(pid1, pid2):
    try:
        return os.getpgid(pid1) == os.getpgid(pid2)
    except ProcessLookupError:
        return False

# Create two child processes
pid1 = os.fork()
if pid1 == 0:
    os._exit(0)  # First child exits immediately

pid2 = os.fork()
if pid2 == 0:
    # Second child creates new group
    os.setpgid(0, 0)
    os._exit(0)

# Parent compares groups
print(f"PID {pid1} and PID {os.getpid()} same group: {are_in_same_group(pid1, os.getpid())}")
print(f"PID {pid2} and PID {os.getpid()} same group: {are_in_same_group(pid2, os.getpid())}")

os.waitpid(pid1, 0)
os.waitpid(pid2, 0)

are_in_same_group 函数比较两个进程的进程组 ID。该示例显示一个子进程保持父进程的组,而另一个子进程创建一个新组。

进程组比较对于作业控制和信号分配场景非常有用。

进程组层次结构

此高级示例通过创建具有不同组关系的多个进程来演示进程组层次结构。

group_hierarchy.py
import os

def print_group_info(pid, name):
    pgid = os.getpgid(pid)
    print(f"{name} (PID: {pid}, PGID: {pgid})")

# Main process
print_group_info(os.getpid(), "Main process")

# First child - same group
pid1 = os.fork()
if pid1 == 0:
    print_group_info(os.getpid(), "Child 1")
    os._exit(0)

# Second child - new group
pid2 = os.fork()
if pid2 == 0:
    os.setpgid(0, 0)
    print_group_info(os.getpid(), "Child 2 (new group)")
    
    # Grandchild - inherits new group
    pid3 = os.fork()
    if pid3 == 0:
        print_group_info(os.getpid(), "Grandchild")
        os._exit(0)
    os.waitpid(pid3, 0)
    os._exit(0)

# Wait for children
os.waitpid(pid1, 0)
os.waitpid(pid2, 0)

这将创建一个进程层次结构,其中 Child 2 启动一个其孙子继承的新组。 Child 1 仍保留在原始组中。

输出显示了进程组如何在进程层次结构中传播,除非显式更改。

安全注意事项

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程