340 likes | 524 Views
Chapter 18 – Process Management. Outline 18.1 Introduction 18.2 os.fork Function 18.3 os.system Function and os.exec Family of Functions 18.4 Controlling Process Input and Output 18.5 Interprocess Communication 18.6 Signal Handling 18.7 Sending Signals. 18.1 Introduction.
E N D
Chapter 18 – Process Management Outline18.1 Introduction18.2 os.fork Function18.3 os.system Function and os.exec Family of Functions18.4 Controlling Process Input and Output18.5 Interprocess Communication18.6 Signal Handling18.7 Sending Signals
18.1 Introduction • Implement concurrency by having each task (or process) operate in a separate memory space • Time slicing on single-processor systems divides processor time among many processes • Operating system allocates a short execution time called a quantum to a process • Operating system performs context switching to move processes and their dependent data in and out of memory
18.1 Introduction • Operating systems provides shells – programs that execute system commands on user’s behalf • Some operating systems have built-in system commands that enable programmers to create and manage processes (e.g. Portable Operating System Interface for UNIX (POSIX) standard defines these system commands for UNIX operating systems)
18.2 os.fork Function • Function os.fork, available only on POSIX-compliant systems, creates a new process • Parent process invokes os.fork • Parent process forks (creates) a child process • Each process has a unique identifying process id number (pid) • Function os.fork’s return value • 0 for child process • Child’s pid for parent
Parent process calls os.fork and assigns return value to forkPID 1 Parent (original) process executes 2 Parent process (forkPID is Child’s pid) Parent process Parent and child processes execute same program simultaneously 3 forkPID = os.fork() Child process (forkPID is 0) 18.2 os.fork Function Fig. 18.1 os.fork creates a new process.
Indicates current process is parent Returns pid Creates duplicate of current process Function os.fork raises OSError exception if new process cannot be created Parent process Child process has pid of 0 Indicates child process 1 # Fig. 18.2: fig18_02.py 2 # Using fork to create child processes. 3 4 import os 5 import sys 6 import time 7 8processName = "parent"# only the parent is running now 9 10 print"Program executing\n\tpid: %d, processName: %s" \ 11 % ( os.getpid(), processName ) 12 13 # attempt to fork child process 14 try: 15 forkPID = os.fork() # create child process 16except OSError: 17 sys.exit( "Unable to create new process." ) 18 19if forkPID != 0: # am I parent process? 20 print"Parent executing\n" + \ 21 "\tpid: %d, forkPID: %d, processName: %s" \ 22 % ( os.getpid(), forkPID, processName ) 23 24elif forkPID == 0: # am I child process? 25 processName = "child" 26 print"Child executing\n" + \ 27 "\tpid: %d, forkPID: %d, processName: %s" \ 28 % ( os.getpid(), forkPID, processName ) 29 30 print"Process finishing\n\tpid: %d, processName: %s" \ 31 % ( os.getpid(), processName ) fig18_02.py
Program executing pid: 5428, processName: parent Parent executing pid: 5428, forkPID: 5429, processName: parent Process finishing pid: 5428, processName: parent Child executing pid: 5429, forkPID: 0, processName: child Process finishing pid: 5429, processName: child Program executing pid: 5430, processName: parent Child executing pid: 5431, forkPID: 0, processName: child Process finishing pid: 5431, processName: child Parent executing pid: 5430, forkPID: 5431, processName: parent Process finishing pid: 5430, processName: parent Program executing pid: 5888, processName: parent Child executing Parent executing pid: 5888, forkPID: 5889, processName: parent Process finishing pid: 5888, processName: parent pid: 5889, forkPID: 0, processName: child Process finishing pid: 5889, processName: child
Generate random sleep times for child processes Create first child process Create second child process 1 # Fig. 18.3: fig18_03.py 2 # Demonstrates the wait function. 3 4 import os 5 import sys 6 import time 7 import random 8 9 # generate random sleep times for child processes 10sleepTime1 = random.randrange( 1, 6 ) 11 sleepTime2 = random.randrange( 1, 6 ) 12 13 # parent ready to fork first child process 14 try: 15 forkPID1 = os.fork() # create first child process 16 except OSError: 17 sys.exit( "Unable to create first child. " ) 18 19 if forkPID1 != 0: # am I parent process? 20 21 # parent ready to fork second child process 22 try: 23 forkPID2 = os.fork() # create second child process 24 except OSError: 25 sys.exit( "Unable to create second child." ) 26 27 if forkPID2 != 0: # am I parent process? 28 print"Parent waiting for child processes...\n" + \ 29 "\tpid: %d, forkPID1: %d, forkPID2: %d" \ 30 % ( os.getpid(), forkPID1, forkPID2 ) 31 fig18_03.py
Function os.wait causes parent to wait for child process to complete execution Function os.wait returns finished child’s pid 32 # wait for any child process 33 try: 34 child1 = os.wait()[ 0 ] # wait returns one child’s pid 35 except OSError: 36 sys.exit( "No more child processes." ) 37 38 print"Parent: Child %d finished first, one child left." \ 39 % child1 40 41 # wait for another child process 42 try: 43 child2 = os.wait()[ 0 ] # wait returns other child’s pid 44 except OSError: 45 sys.exit( "No more child processes." ) 46 47 print"Parent: Child %d finished second, no children left." \ 48 % child2 49 50 elif forkPID2 == 0: # am I second child process? 51 print"""Child2 sleeping for %d seconds... 52 \tpid: %d, forkPID1: %d, forkPID2: %d""" \ 53 % ( sleepTime2, os.getpid(), forkPID1, forkPID2 ) 54 time.sleep(sleepTime2 ) # sleep to simulate some work 55 56 elif forkPID1 == 0: # am I first child process? 57 print"""Child1 sleeping for %d seconds... 58 \tpid: %d, forkPID1: %d""" \ 59 % ( sleepTime1, os.getpid(), forkPID1 ) 60 time.sleep(sleepTime1 ) # sleep to simulate some work fig18_03.py
Child2 sleeping for 4 seconds... pid: 9578, forkPID1: 9577, forkPID2: 0 Child1 sleeping for 5 seconds... pid: 9577, forkPID1: 0 Parent waiting for child processes... pid: 9576, forkPID1: 9577, forkPID2: 9578 Parent: Child 9578 finished first, one child left. Parent: Child 9577 finished second, no children left. Parent waiting for child processes... pid: 9579, forkPID1: 9580, forkPID2: 9581 Child1 sleeping for 1 seconds... pid: 9580, forkPID1: 0 Child2 sleeping for 5 seconds... pid: 9581, forkPID1: 9580, forkPID2: 0 Parent: Child 9580 finished first, one child left. Parent: Child 9581 finished second, no children left. Parent waiting for child processes... Child1 sleeping for 4 seconds... pid: 9583, forkPID1: 0 Child2 sleeping for 3 seconds... pid: 9584, forkPID1: 9583, forkPID2: 0 pid: 9582, forkPID1: 9583, forkPID2: 9584 Parent: Child 9584 finished first, one child left. Parent: Child 9583 finished second, no children left.
Create first child process Create second child process Wait explicitly for second child by specifying its pid 1 # Fig. 18.4: fig18_04.py 2 # Demonstrates the waitpid function. 3 4 import os 5 import sys 6 import time 7 8 # parent about to fork first child process 9 try: 10 forkPID1 = os.fork() # create first child process 11 except OSError: 12 sys.exit( "Unable to create first child. " ) 13 14 if forkPID1 != 0: # am I parent process? 15 16 # parent about to fork second child process 17 try: 18 forkPID2 = os.fork() # create second child process 19 except OSError: 20 sys.exit( "Unable to create second child." ) 21 22 if forkPID2 > 0: # am I parent process? 23 print"Parent waiting for child processes...\n" + \ 24 "\tpid: %d, forkPID1: %d, forkPID2: %d" \ 25 % ( os.getpid(), forkPID1, forkPID2 ) 26 27 # wait for second child process explicitly 28 try: 29 child2 = os.waitpid( forkPID2, 0 )[ 0 ] # child’s pid 30 except OSError: 31 sys.exit( "No child process with pid %d." % ( forkPID2 ) ) 32 33 print"Parent: Child %d finished." \ 34 % child2 35 fig18_04.py
36 elif forkPID2 == 0: # am I second child process? 37 print"Child2 sleeping for 4 seconds...\n" + \ 38 "\tpid: %d, forkPID1: %d, forkPID2: %d" \ 39 % ( os.getpid(), forkPID1, forkPID2 ) 40 time.sleep( 4 ) 41 42 elif forkPID1 == 0: # am I first child process? 43 print"Child1 sleeping for 2 seconds...\n" + \ 44 "\tpid: %d, forkPID1: %d" % ( os.getpid(), forkPID1 ) 45 time.sleep( 2 ) fig18_04.py Parent waiting for child processes...pid: 6092, forkPID1: 6093, forkPID2: 6094Child1 sleeping for 2 seconds... pid: 6093, forkPID1: 0Child2 sleeping for 4 seconds... pid: 6094, forkPID1: 6093, forkPID2: 0Parent: Child 6094 finished. Child1 sleeping for 2 seconds... pid: 6089, forkPID: 0Child2 sleeping for 4 seconds... pid: 6090, forkPID: 6089, forkPID2: 0Parent waiting for child processes... pid: 6088, forkPID: 6089, forkPID2: 6090Parent: Child 6090 finished. Parent waiting for child processes... Child1 sleeping for 2 seconds... pid: 6102, forkPID: 0 pid: 6101, forkPID: 6102, forkPID2: 6103 Child2 sleeping for 4 seconds... pid: 6103, forkPID: 6102, forkPID2: 0 Parent: Child 6103 finished.
18.3 os.system Function and os.exec Family of Functions • Function os.system executes a system command using a shell and then returns control to the original process (after the command completes) • os.exec family of functions do not return control to calling process after executing the specified command
Function os.system executes system-specific clear command Clear command depends on operating system 1 # Fig. 18.5: fig18_05.py 2 # Uses the system function to clear the screen. 3 4 import os 5 import sys 6 7 def printInstructions( clearCommand ): 8 os.system( clearCommand ) # clear display 9 10 print"""Type the text that you wish to save in this file. 11 Type clear on a blank line to delete the contents of the file. 12 Type quit on a blank line when you are finished.\n""" 13 14 # determine operating system 15if os.name == "nt"or os.name == "dos": # Windows system 16 clearCommand = "cls" 17 print"You are using a Windows system." 18 elif os.name == "posix": # UNIX-compatible system 19 clearCommand = "clear" 20 print"You are using a UNIX-compatible system." 21 else: 22 sys.exit( "Unsupported OS" ) 23 24 filename = raw_input( "What file would you like to create? " ) 25 26 # open file 27 try: 28 file = open( filename, "w+" ) 29 except IOError, message: 30 sys.exit( "Error creating file: %s" % message ) 31 32 printInstructions( clearCommand ) 33 currentLine = "" 34 fig18_05.py
Write user input to file Truncate file if user enters clear Call printInstructions to clear console and display instructions again 35 # write input to file 36while currentLine != "quit\n": 37 file.write( currentLine ) 38 currentLine = sys.stdin.readline() 39 40if currentLine == "clear\n": 41 42 # seek to beginning and truncate file 43 file.seek( 0, 0 ) 44 file.truncate() 45 46 currentLine = "" 47 printInstructions( clearCommand ) 48 49 file.close() fig18_05.py You are using a Windows system.What file would you like to create? welcome.txt You are using a UNIX-compatible system.What file would you like to create? welcome.txt Type the text that you wish to save in this file.Type clear on a blank line to delete the contents of the file.Type quit on a blank line when you are finished.This will not be written to the file.The following line will call clear.clear
Type the text that you wish to save in this file. Type clear on a blank line to delete the contents of the file. Type quit on a blank line when you are finished. Type the text that you wish to save in this file. Type clear on a blank line to delete the contents of the file. Type quit on a blank line when you are finished. Wilkommen! Bienvenue! Welcome! quit Wilkommen! Bienvenue! Welcome!
Program requires 2 command-line arguments: URL name and filename Determine operating system and set appropriate editor command Retrieve Web page and store its contents in the specified file Replaces current process with text editor application Function os.execvp takes two arguments: command name and its arguments 1 # Fig. 18.7: fig18_07.py 2 # Opens a Web page in a system-specific editor. 3 4 import os 5 import sys 6 import urllib 7 8if len( sys.argv ) != 3: 9 sys.exit( "Incorrect number of arguments." ) 10 11 # determine operating system and set editor command 12if os.name == "nt"or os.name == "dos": 13 editor = "notepad.exe" 14 elif os.name == "posix": 15 editor = "vi" 16 else: 17 sys.exit( "Unsupported OS" ) 18 19 # obtain Web page and store in file 20urllib.urlretrieve( sys.argv[ 1 ], sys.argv[ 2 ] ) 21 22 # editor expects to receive itself as an argument 23os.execvp( editor, ( editor, sys.argv[ 2 ] ) ) 24 25 print"This line never executes." fig18_07.py fig18_07.py http://www.deitel.com/test/test.txt test.txt This is a test file to illustratedownloading text from a file on aweb server using an HTTP connectionto the server.~~~
18.3 os.system Function and os.exec Family of Functions Fig. 18.8 exec family of functions.
18.4 Controlling Process Input and Output • UNIX-system users can use multiple programs together to achieve a particular result (e.g., ls|sort produces a sorted list of a directory’s contents)
Determine operating system to set system-specific directory-listing and reverse-sort commands Executes command and obtains stdout stream Executes command and obtains stdout and stdin streams Returns directory-listing command’s output Sends directory-listing command’s output to reverse-sort command’s stdin stream Close stdout stream of directory-listing command Closing stdin stream of sort command sends EOF 1 # Fig. 18.9: fig18_09.py 2 # Demonstrating popen and popen2. 3 4 import os 5 6 # determine operating system, then set directory-listing and 7 # reverse-sort commands 8if os.name == "nt"or os.name == "dos": # Windows system 9 fileList = "dir /B" 10 sortReverse = "sort /R" 11 elif os.name == "posix": # UNIX-compatible system 12 fileList = "ls -1" 13 sortReverse = "sort -r" 14 else: 15 sys.exit( "OS not supported by this program." ) 16 17 # obtain stdout of directory-listing command 18dirOut = os.popen( fileList, "r" ) 19 20 # obtain stdin, stdout of reverse-sort command 21sortIn, sortOut = os.popen2( sortReverse ) 22 23filenames = dirOut.read() # output from directory-listing command 24 25 # display output from directory-listing command 26 print"Before sending to sort" 27 print"(Output from ’%s’):" % fileList 28 print filenames 29 30sortIn.write( filenames ) # send to stdin of sort command 31 32dirOut.close() # close stdout of directory-listing command 33sortIn.close() # close stdin of sort command -- sends EOF 34 fig18_09.py
Retrieve directory list sorted in reverse order Close sort command’s stdout stream 35 # display output from sort command 36 print"After sending to sort" 37 print"(Output from ’%s’):" % sortReverse 38print sortOut.read() # output from sort command 39 40sortOut.close() # close stdout of sort command fig18_09.py Before sending to sort (Output from 'ls -1'): fig18_02.py fig18_03.py fig18_04.py fig18_05.py fig18_07.py fig18_09.py fig18_10.py fig18_14.py fig18_15.py After sending to sort (Output from 'sort -r'): fig18_15.py fig18_14.py fig18_10.py fig18_09.py fig18_07.py fig18_05.py fig18_04.py fig18_03.py fig18_02.py
Before sending to sort (Output from 'dir /B'): fig18_02.py fig18_03.py fig18_04.py fig18_05.py fig18_07.py fig18_09.py fig18_10.py fig18_14.py fig18_15.py After sending to sort (Output from 'sort /R'): fig18_15.py fig18_14.py fig18_10.py fig18_09.py fig18_07.py fig18_05.py fig18_04.py fig18_03.py fig18_02.py
18.5 Interprocess Communication • Module os provides interface to many interprocess communication (IPC) mechanisms • Pipe, IPC mechanism, is a file-like object that provides a one-way communication channel • Function os.pipe creates a pipe and returns a tuple containing two file descriptors which provide read and write access to the pipe • Functions os.read and os.write read and write the files associated with the file descriptors
Open parent and child read/write pipes Close unnecessary pipe ends for parent Write values 1-10 to parent’s write pipe Read values from child’s read pipe Close remaining pipes 1 # Fig. 18.10: fig18_10.py 2 # Using os.pipe to communicate with a child process. 3 4 import os 5 import sys 6 7 # open parent and child read/write pipes 8fromParent, toChild = os.pipe() 9 fromChild, toParent = os.pipe() 10 11 # parent about to fork child process 12 try: 13 pid = os.fork() # create child process 14 except OSError: 15 sys.exit( "Unable to create child process." ) 16 17 if pid != 0: # am I parent process? 18 19 # close unnecessary pipe ends 20 os.close( toParent ) 21 os.close( fromParent ) 22 23 # write values from 1-10 to parent’s write pipe and 24 # read 10 values from child’s read pipe 25 for i in range( 1, 11 ): 26 os.write( toChild, str( i ) ) 27 print"Parent: %d," % i, 28 print"Child: %s" % \ 29 os.read( fromChild, 64 ) 30 31 # close pipes 32 os.close( toChild ) 33 os.close( fromChild ) 34 fig18_10.py
Close pipe ends unnecessary for child process Read value from parent pipe Write number to child write pipe Read more data from parent read pipe Close remaining pipes Terminates child process without any cleanup 35 elif pid == 0: # am I child process? 36 37 # close unnecessary pipe ends 38 os.close( toChild ) 39 os.close( fromChild ) 40 41 # read value from parent pipe 42 currentNumber = os.read( fromParent, 64 ) 43 44 # if we receive number from parent, 45 # write number to child write pipe 46 while currentNumber: 47 newNumber = int( currentNumber ) * 20 48 os.write( toParent, str( newNumber ) ) 49 currentNumber = os.read( fromParent, 64 ) 50 51 # close pipes 52 os.close( toParent ) 53 os.close( fromParent ) 54 os._exit( 0 ) # terminate child process fig18_10.py Parent: 1, Child: 20 Parent: 2, Child: 40 Parent: 3, Child: 60 Parent: 4, Child: 80 Parent: 5, Child: 100 Parent: 6, Child: 120 Parent: 7, Child: 140 Parent: 8, Child: 160 Parent: 9, Child: 180 Parent: 10, Child: 200
Read end Write end Parent pipe Original process Child pipe Read end Write end 18.5 Interprocess Communication Original process can write to either parent or child pipe Original process can read from either parent or child pipe Fig. 18.11 Initial stage: Original process can read and write to both pipes.
Parent process Read end Write end Parent pipe Child process can read from parent and child pipe Child process can write to parent and child pipe Child process Child pipe Read end Write end 18.5 Interprocess Communication Patent process can read from parent and child pipe Patent process can write to parent and child pipe Fig. 18.12 Intermediate stage: Parent and child processes can read and write to both pipes.
Parent process Read end Write end Parent pipe Child process Child pipe Read end Write end 18.5 Interprocess Communication Child process reads from parent pipe and writes to child pipe Parent process reads from child pipe and writes to parent pipe Fig. 18.13 Final stage: Parent and child processes close unneeded ends of the pipes.
18.6 Signal Handling • Processes can communicate with signals, which are messages that operating systems deliver to programs asynchronously • Signal processing: program receives a signal and performs an action based on that signal • Signal handlers execute in response to signals • Every Python program has default signal handlers
Module signal provides signal-handling capabilities Signal handlers take two arguments: signal and current stack frame Registers signal signal.SIGINT with function stop 1 # Fig. 18.14: fig18_14.py 2 # Defining our own signal handler. 3 4 import time 5import signal 6 7def stop( signalNumber, frame ): 8 global keepRunning 9 keepRunning -= 1 10 print"Ctrl-C pressed; keepRunning is", keepRunning 11 12 keepRunning = 3 13 14 # set the handler for SIGINT to be function stop 15signal.signal( signal.SIGINT, stop ) 16 17 while keepRunning: 18 print"Executing..." 19 time.sleep( 1 ) 20 21 print "Program terminating..." fig18_14.py Executing... Executing... Ctrl-C pressed; keepRunning is 2 Executing... Executing... Ctrl-C pressed; keepRunning is 1 Executing... Executing... Ctrl-C pressed; keepRunning is 0 Program terminating...
18.7 Sending Signals • Executing programs can send signals to other processes • Function os.kill sends a signal to a particular process identified by its pid
Signal handler enables parent process to handle interrupt signal Sends kill signal signal.SIGKILL to process with specified pid Register parent’s handler for signal.SIGINT 1 # Fig. 18.15: fig18_15.py 2 # Sending signals to child processes using kill 3 4 import os 5 import signal 6 import time 7 import sys 8 9 # handles both SIGALRM and SIGINT signals 10def parentInterruptHandler( signum, frame ): 11 global pid 12 global parentKeepRunning 13 14 # send kill signal to child process and exit 15 os.kill( pid, signal.SIGKILL ) # send kill signal 16 print"Interrupt received. Child process killed." 17 18 # allow parent process to terminate normally 19 parentKeepRunning = 0 20 21 # set parent's handler for SIGINT 22signal.signal( signal.SIGINT, parentInterruptHandler ) 23 24 # keep parent running until child process is killed 25 parentKeepRunning = 1 26 27 # parent ready to fork child process 28 try: 29 pid = os.fork() # create child process 30 except OSError: 31 sys.exit( "Unable to create child process." ) 32 33 if pid != 0: # am I parent process? 34 fig18_15.py
Ignore interrupt signal in child process 35 while parentKeepRunning: 36 print"Parent running. Press Ctrl-C to terminate child." 37 time.sleep( 1 ) 38 39 elif pid == 0: # am I child process? 40 41 # ignore interrupt in child process 42 signal.signal( signal.SIGINT, signal.SIG_IGN ) 43 44 while 1: 45 print"Child still executing." 46 time.sleep( 1 ) 47 48 print"Parent terminated child process." 49 print"Parent terminating normally." fig18_15.py Parent running. Press Ctrl-C to terminate child. Child still executing. Parent running. Press Ctrl-C to terminate child. Child still executing. Child still executing. Parent running. Press Ctrl-C to terminate child. Interrupt received. Child process killed. Parent terminated child process. Parent terminating normally.