ZetCode

Python os.getpgrp Function

Last modified April 11, 2025

This comprehensive guide explores Python's os.getpgrp function, which retrieves the process group ID of the current process. We'll cover Unix process groups, session management, and practical examples.

Basic Definitions

The os.getpgrp function returns the process group ID of the current process. Process groups are used by Unix systems to manage job control.

A process group is a collection of related processes that can receive signals as a unit. The process group ID is typically the PID of the group leader.

Getting Current Process Group ID

The simplest use of os.getpgrp retrieves the current process's group ID. This example shows basic usage and compares it with the process 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")

This example shows the relationship between process ID and process group ID. When they match, the process is the group leader.

New processes typically inherit their parent's process group unless explicitly changed with os.setpgrp or similar functions.

Comparing Parent and Child Process Groups

This example demonstrates how process groups are inherited when creating child processes using 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)

The child process inherits the parent's process group by default. Both processes will show the same process group ID in the output.

This behavior is fundamental to Unix process management and job control mechanisms.

Creating New Process Groups

This example shows how to create a new process group using os.setpgrp and verify it with 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")

After calling os.setpgrp, the process becomes leader of a new process group with its PID as the group ID.

This is commonly done by shell programs when starting new job control sessions.

Process Groups and Terminal Control

This example demonstrates how process groups relate to terminal control and signal handling.

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)

Run this script and press Ctrl+C to see how the signal is delivered to both processes in the same group.

Process groups determine which processes receive terminal-generated signals like SIGINT (Ctrl+C) and SIGTSTP (Ctrl+Z).

Session Management Example

This advanced example demonstrates process groups in the context of session management, showing how os.getpgrp relates to session IDs.

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

The child process creates a new session with os.setsid, becoming both session leader and process group leader.

Note that os.setsid also creates a new process group automatically.

Process Group in Shell Jobs

This example simulates how shells manage process groups for job control, demonstrating foreground and background process groups.

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)

The example shows how shells typically create separate process groups for foreground and background jobs.

Background jobs get their own process group to prevent them from receiving terminal signals meant for foreground processes.

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.