ZetCode

Python os.getpgrp 函数

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

这份综合指南探讨了 Python 的 os.getpgrp 函数,该函数用于检索当前进程的进程组 ID。我们将涵盖 Unix 进程组、会话管理和实践示例。

基本定义

os.getpgrp 函数返回当前进程的进程组 ID。进程组由 Unix 系统用于管理作业控制。

进程组是相关进程的集合,可以作为一个单元接收信号。进程组 ID 通常是组领导者的 PID。

获取当前进程组 ID

os.getpgrp 最简单的用法是检索当前进程的组 ID。 此示例展示了基本用法,并将其与进程 ID 进行比较。

basic_usage.py
import os

# Get current process group ID
pgrp = os.getpgrp()
pid = os.getpid()

print(f"Process ID: {pid}")
print(f"Process Group ID: {pgrp}")

# Check if process is group leader
if pid == pgrp:
    print("This process is the group leader")
else:
    print("This process is not the group leader")

此示例展示了进程 ID 和进程组 ID 之间的关系。 当它们匹配时,该进程是组领导者。

除非使用 os.setpgrp 或类似函数显式更改,否则新进程通常会继承其父进程的进程组。

比较父进程和子进程的进程组

此示例演示了在使用 os.fork 创建子进程时如何继承进程组。

fork_example.py
import os

print(f"Parent PID: {os.getpid()}, PGID: {os.getpgrp()}")

child_pid = os.fork()

if child_pid == 0:
    # Child process
    print(f"Child PID: {os.getpid()}, PGID: {os.getpgrp()}")
else:
    # Parent process
    os.waitpid(child_pid, 0)

默认情况下,子进程继承父进程的进程组。 两个进程将在输出中显示相同的进程组 ID。

此行为是 Unix 进程管理和作业控制机制的基础。

创建新的进程组

此示例演示了如何使用 os.setpgrp 创建新的进程组,并使用 os.getpgrp 验证它。

new_group.py
import os

print(f"Original PGID: {os.getpgrp()}")

# Create new process group
os.setpgrp()

print(f"New PGID: {os.getpgrp()}")

# Verify we're now the group leader
if os.getpid() == os.getpgrp():
    print("Successfully created new process group")
else:
    print("Failed to create new process group")

调用 os.setpgrp 后,该进程将成为新进程组的领导者,其 PID 作为组 ID。

通常由 shell 程序在启动新的作业控制会话时执行此操作。

进程组和终端控制

此示例演示了进程组如何与终端控制和信号处理相关。

terminal_control.py
import os
import signal
import time

def handler(signum, frame):
    print(f"Received signal {signum} in process {os.getpid()}")

# Set up signal handler
signal.signal(signal.SIGINT, handler)

print(f"Process {os.getpid()} in group {os.getpgrp()}")

# Fork a child process
child_pid = os.fork()

if child_pid == 0:
    # Child process
    print(f"Child {os.getpid()} in group {os.getpgrp()}")
    time.sleep(10)
else:
    # Parent process
    print(f"Parent {os.getpid()} waiting")
    os.waitpid(child_pid, 0)

运行此脚本并按 Ctrl+C,以查看信号如何传递到同一组中的两个进程。

进程组确定哪些进程接收终端生成的信号,例如 SIGINT (Ctrl+C) 和 SIGTSTP (Ctrl+Z)。

会话管理示例

这个高级示例演示了会话管理上下文中的进程组,展示了 os.getpgrp 如何与会话 ID 相关。

session_example.py
import os

def print_ids():
    print(f"PID: {os.getpid()}")
    print(f"PGID: {os.getpgrp()}")
    print(f"SID: {os.getsid(0)}")
    print()

print("Original process:")
print_ids()

# Create new session
if os.fork() == 0:
    os.setsid()
    print("After setsid():")
    print_ids()
    os._exit(0)

os.wait()

子进程使用 os.setsid 创建一个新会话,同时成为会话领导者和进程组领导者。

请注意,os.setsid 也会自动创建一个新的进程组。

Shell 作业中的进程组

此示例模拟了 shell 如何管理作业控制的进程组,演示了前台和后台进程组。

shell_jobs.py
import os
import time

def worker(name):
    print(f"{name} PID: {os.getpid()}, PGID: {os.getpgrp()}")
    time.sleep(5)

# Simulate shell job control
print(f"Shell PID: {os.getpid()}, PGID: {os.getpgrp()}")

# Create foreground process group
foreground = os.fork()
if foreground == 0:
    worker("Foreground")
    os._exit(0)

# Create background process group
background = os.fork()
if background == 0:
    os.setpgrp()
    worker("Background")
    os._exit(0)

os.waitpid(foreground, 0)
os.waitpid(background, 0)

该示例展示了 shell 通常如何为前台和后台作业创建单独的进程组。

后台作业获得自己的进程组,以防止它们接收旨在用于前台进程的终端信号。

安全注意事项

最佳实践

资料来源

作者

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

列出所有 Python 教程