๐น Advanced Process Control
Master process management, job control, and resource allocation for efficient shell scripting.
๐งญ Process Lifecycle Management
Understanding how processes are created, managed, and terminated is essential for robust scripts.
Process States
Processes transition through several states:
- Running โ Currently executing
- Sleeping โ Waiting for resource/event
- Stopped โ Suspended (SIGSTOP)
- Zombie โ Terminated but not reaped by parent
Monitor with:
| ps aux --forest
top -p $$
htop
|
๐งช Job Control Deep Dive
Background Jobs
Launch detached processes:
| long_running_task &
BG_PID=$!
echo "Background job PID: $BG_PID"
# Wait for specific job
wait $BG_PID
|
Job Identification
| # List all jobs with details
jobs -l
# Output format:
# [1]+ 12345 Running long_task &
# [2]- 12346 Stopped other_task
|
Job specifiers:
- %1, %2 โ Job numbers
- %+ โ Current job (default)
- %- โ Previous job
- %string โ Job containing string
- %?pattern โ Job matching pattern
๐ง Process Priority Management
Nice Values
Adjust CPU scheduling priority (-20 to 19):
| # Start with low priority
nice -n 10 low_priority_job
# Change priority of running process
renice +5 $PID
# View nice values
ps -o pid,nice,comm
|
Resource Limits
Control resource consumption:
| # Set CPU time limit (seconds)
ulimit -t 30
# Set virtual memory limit (KB)
ulimit -v 1000000
# Set file size limit
ulimit -f 1000000
# View all limits
ulimit -a
|
๐งช Process Groups and Sessions
Process Group Management
| # Create new process group
setpgid 0 0
# Send signal to process group
kill -TERM -$PGID
# View process groups
ps -o pid,pgid,sid,comm
|
Session Leadership
| # Create new session (detaches from controlling terminal)
setsid my_daemon
# Check session ID
ps -o sid= -p $$
|
๐ง Advanced Daemonization
Proper Daemon Pattern
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | daemonize() {
# First fork
case $(fork) in
0)
# Second fork
case $(fork) in
0)
# Child of second fork
cd /
umask 0
exec 0</dev/null
exec 1>/dev/null
exec 2>/dev/null
# Run actual daemon
exec "$@"
;;
*)
# Parent of second fork - exit
exit 0
;;
esac
;;
*)
# Parent of first fork - wait and exit
wait
exit 0
;;
esac
}
# Usage
daemonize /usr/local/bin/my_service
|
Using nohup
Simple daemonization:
| nohup my_script.sh > output.log 2>&1 &
disown
|
๐งช Signal Handling for Processes
Custom Signal Actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | handle_usr1() {
echo "Received USR1 - reloading config"
reload_configuration
}
handle_usr2() {
echo "Received USR2 - rotating logs"
rotate_logs
}
# Set up handlers
trap handle_usr1 USR1
trap handle_usr2 USR2
# Send signals
kill -USR1 $PID
kill -USR2 $PID
|
Graceful Shutdown
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | shutdown_requested=false
graceful_shutdown() {
echo "Shutdown requested..."
shutdown_requested=true
}
trap graceful_shutdown TERM INT
while [ "$shutdown_requested" = false ]; do
do_work
sleep 1
done
cleanup_resources
exit 0
|
๐ง Process Monitoring and Debugging
Live Process Monitoring
| # Monitor specific process
watch -n 1 "ps -p $PID -o pid,ppid,pcpu,pmem,etime,comm"
# Monitor resource usage
top -p $PID
htop -p $PID
# Trace system calls
strace -p $PID
|
Process Tree Analysis
| # Show process tree
pstree -p $$
# Find child processes
pgrep -P $$
# Kill entire process tree
pkill -P $$ # Children
kill -TERM $$ # Self
|
๐งช Concurrency Control
Limit Concurrent Jobs
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | max_concurrent=4
current_jobs=0
for item in "${items[@]}"; do
process_item "$item" &
current_jobs=$((current_jobs + 1))
if [ $current_jobs -ge $max_concurrent ]; then
wait # Wait for batch to complete
current_jobs=0
fi
done
wait # Wait for final batch
|
Semaphore Pattern
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | # Create semaphore file
semaphore="/tmp/job_semaphore"
max_jobs=4
acquire_semaphore() {
while [ $(ls $semaphore.* 2>/dev/null | wc -l) -ge $max_jobs ]; do
sleep 0.1
done
touch "$semaphore.$$"
}
release_semaphore() {
rm -f "$semaphore.$$"
}
# Usage
acquire_semaphore
process_item &
release_semaphore
|
CPU Affinity
Bind processes to specific cores:
| # Bind to CPU 0
taskset -c 0 my_process
# View current affinity
taskset -p $PID
|
I/O Scheduling
Adjust I/O priority:
| # Low I/O priority
ionice -c 3 my_process
# High I/O priority
ionice -c 1 my_process
|
Memory Locking
Prevent swapping:
| # Lock pages in memory
mlockall my_critical_process
|
๐งพ Summary
- Master job control with
&, wait, jobs
- Use
nice/renice for priority management
- Implement proper daemonization patterns
- Handle signals for graceful operation
- Monitor processes with
ps, top, strace
- Control concurrency to prevent overload
- Tune performance with affinity and I/O scheduling
- Understand process states and lifecycle
๐ Continue to: Signals and Job Control