ZetCode

Python os.getpgid Function

Last modified April 11, 2025

This comprehensive guide explores Python's os.getpgid function, which retrieves process group IDs. We'll cover Unix process groups, practical usage examples, and related process management functions.

Basic Definitions

The os.getpgid function returns the process group ID of the process with specified process ID (pid). Process groups are Unix constructs for job control and signal distribution.

Key parameter: pid (process ID to query, 0 means current process). Returns the process group ID as an integer. Raises ProcessLookupError for invalid pid.

Getting Current Process Group ID

The simplest use of os.getpgid retrieves the current process's group ID by passing 0 as the pid parameter. This is often used as a reference.

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()")

This example shows how to get the current process group ID. It also demonstrates that os.getpgid(0) is equivalent to os.getpgrp().

The process group ID is typically the same as the process ID of the group leader (the first process in the group).

Getting Child Process Group ID

When creating child processes, you can check their process group IDs. This example forks a child process and examines its group 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)

The parent process retrieves both its own and the child's process group ID. By default, the child inherits the parent's process group.

This demonstrates how process groups are typically inherited unless explicitly changed with os.setpgid().

Changing Process Group

This example shows how to create a new process group and verify the change using 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

The child process creates a new process group with itself as the leader. The parent verifies the child's new group ID matches its process ID.

This is commonly done by shells when creating new job control groups for command pipelines.

Handling Invalid Process ID

os.getpgid raises ProcessLookupError when given an invalid process ID. This example demonstrates proper error handling.

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

The safe_getpgid function gracefully handles invalid process IDs by catching ProcessLookupError. This prevents crashes when querying arbitrary processes.

Always validate process IDs or handle exceptions when working with process management functions.

Comparing Process Groups

This example demonstrates comparing process group IDs to determine if processes belong to the same group.

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)

The are_in_same_group function compares process group IDs of two processes. The example shows one child keeping the parent's group while another creates a new group.

Process group comparisons are useful for job control and signal distribution scenarios.

Process Group Hierarchy

This advanced example demonstrates process group hierarchy by creating multiple processes with different group relationships.

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)

This creates a process hierarchy where Child 2 starts a new group that its grandchild inherits. Child 1 remains in the original group.

The output shows how process groups propagate through the process hierarchy unless explicitly changed.

Security Considerations

Best Practices

Source References

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.