Last Updated on September 12, 2022
You can set an exit code for a process via sys.exit() and retrieve the exit code via the exitcode attribute on the multiprocessing.Process class.
In this tutorial you will discover how to get and set exit codes for processes in Python.
Let’s get started.
Need Process Exit Codes
A process is a running instance of a computer program.
Every Python program is executed in a Process, which is a new instance of the Python interpreter. This process has the name MainProcess and has one thread used to execute the program instructions called the MainThread. Both processes and threads are created and managed by the underlying operating system.
Sometimes we may need to create new child processes in our program in order to execute code concurrently.
Python provides the ability to create and manage new processes via the multiprocessing.Process class.
In multiprocessing, we may need to report the success or failure of a task executed by a child process to other processes.
This can be achieved using exit codes.
What are exit codes and how can we use them between processes in Python?
Run loops using all CPUs, download your FREE book to learn how.
How to Use Exit Codes in Python
An exit code or exit status is a way for one process to share with another whether it is finished and if so whether it finished successfully or not.
The exit status of a process in computer programming is a small number passed from a child process (or callee) to a parent process (or caller) when it has finished executing a specific procedure or delegated task.
— Exit status, Wikipedia.
An exit code is typically an integer value to represent success or failure of the process, but may also have an associated string message.
Let’s take a closer look at how we might set an exit code in a process and how another process might check the exit code of a process.
How to Set an Exit Code
A process can set the exit code automatically or explicitly.
For example, if the process exits normally, the exit code will be set to zero. If the process terminated with an error or exception, the exit code will be set to one.
A process can also set its exit code when explicitly exiting.
This can be achieved by calling the sys.exit() function and passing the exit code as an argument.
The sys.exit() function will raise a SystemExit exception in the current process, which will terminate the process.
The optional argument arg can be an integer giving the exit status (defaulting to zero), or another type of object.
— sys — System-specific parameters and functions
This function must be called in the main thread of the process and assumes that the SystemExit exception is not handled.
An argument value of 0 indicates a successful exit.
For example:
1 2 3 |
... # exit successfully sys.exit(0) |
This is the default value of the argument and does not need to be specified.
For example:
1 2 3 |
... # exit successfully sys.exit() |
Passing a value of None as an argument will also be interpreted as a successful exit.
For example:
1 2 3 |
... # exit successfully sys.exit(None) |
A positive integer value indicates an unsuccessful exit, typically a value of one.
For example:
1 2 3 |
... # exit unsuccessfully sys.exit(1) |
Alternatively, a string message may be provided as an argument.
This will be interpreted as an unsuccessful exit, e.g. a value of one, and the message will be reported on stderr.
For example:
1 2 3 |
... # exit unsuccessfully sys.exit('Something bad happened') |
You can learn more about the sys.exit() function in the tutorial:
How to Get An Exit Code
Another process can get the exit code of a process via the “exitcode” attribute of the multiprocessing.Process instance for the process.
For example:
1 2 3 |
... # get the exit code code = process.exitcode |
This means that we require a multiprocessing.Process instance for the process. For example, we may hang on to the process instance when creating the child process.
The exitcode attribute contains the value set by the process calling sys.exit(), or the value set automatically if the process ended normally or with an error.
If the child’s run() method returned normally, the exit code will be 0. If it terminated via sys.exit() with an integer argument N, the exit code will be N.
— multiprocessing — Process-based parallelism
If the process has not yet terminated, the exitcode value will not be set and will have the value None.
Common Exit Code Values
We may set exit codes for a process that are meaningful to the application.
This allows one process to communicate with another process regarding its specific status upon exit.
Additionally, there are also some commonly used exit code values.
For example, the integer value is typically between 0-255 and values 0-127 may be reserved for common situations or errors.
If it is an integer, zero is considered “successful termination” and any nonzero value is considered “abnormal termination” by shells and the like. Most systems require it to be in the range 0–127, and produce undefined results otherwise.
— sys — System-specific parameters and functions
For example:
- 0, None: Success
- 1: Error
- 2: Command line syntax errors
- 120: Error during process cleanup.
- 255: Exit code out of range.
A negative exit code may be assigned to a process if the process was terminated via a specific signal.
If it was terminated by signal N, the exit code will be the negative value -N.
— multiprocessing — Process-based parallelism
Now that we know how to get and set exit codes for a process, let’s look at some worked examples.
Explicit Exit Codes
This section provides examples of explicitly setting an exit code when terminating a process.
Example of Successful Exit Code
We can explore setting a successful exit code in a child process.
In this example we will create a child process to exit a custom function. The child process will block for one second, and then exit with an explicitly successful exit code.
First, we can define the function to execute in the child function.
The function will sleep for a second, then call the sys.exit() function with an argument of zero to indicate a successful exit.
The task() function below implements this.
1 2 3 4 5 6 |
# function executed in a child process def task(): # block for a moment sleep(1) # exit successfully exit(0) |
Next, in the main process, we will configure a new process instance to execute our task() function.
1 2 3 |
... # configure a new process child = Process(target=task) |
The process is then started, and the main process blocks until the child process terminates.
1 2 3 4 5 |
... # start the child process child.start() # wait for the child process to finish child.join() |
Finally, the main process retrieves the exit code for the child process and reports the value.
1 2 3 4 |
... # check the exit code for the child process code = child.exitcode print(f'Child exit code: {code}') |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# SuperFastPython.com # example of a successful exit code from time import sleep from multiprocessing import Process from sys import exit # function executed in a child process def task(): # block for a moment sleep(1) # exit successfully exit(0) # protect the entry point if __name__ == '__main__': # configure a new process child = Process(target=task) # start the child process child.start() # wait for the child process to finish child.join() # check the exit code for the child process code = child.exitcode print(f'Child exit code: {code}') |
Running the example first creates and starts the child process.
The main process then blocks until the child process terminates.
The child process sleeps for one second, then exits with an exit code of zero, indicating success.
The child process terminates then the main process continues on. It retrieves the exit code from the child process and reports the value.
In this case, we can see it has the value zero that we set in the child process when calling exit().
1 |
Child exit code: 0 |
Next, let’s look at an example of an unsuccessful exit code.
Example of Unsuccessful Exit Code
We can explore an unsuccessful exit code.
Recall that any value other than zero indicates an unsuccessful end to the process.
We can update the example from the previous section so that the process calls exit() with a value of one.
1 2 3 |
... # exit unsuccessfully exit(1) |
The updated task() function with this change is listed below.
1 2 3 4 5 6 |
# function executed in a child process def task(): # block for a moment sleep(1) # exit unsuccessfully exit(1) |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# SuperFastPython.com # example of an unsuccessful exit code from time import sleep from multiprocessing import Process from sys import exit # function executed in a child process def task(): # block for a moment sleep(1) # exit unsuccessfully exit(1) # protect the entry point if __name__ == '__main__': # configure a new process child = Process(target=task) # start the child process child.start() # wait for the child process to finish child.join() # check the exit code for the child process code = child.exitcode print(f'Child exit code: {code}') |
Running the example first creates and starts the child process.
The main process then blocks until the child process terminates.
The child process sleeps for one second, then exits with an exit code of one, indicating an unsuccessful exit.
The child process terminates then the main process continues on. It retrieves the exit code from the child process and reports the value.
In this case, we can see it has the value of one that we set in the child process when calling exit().
1 |
Child exit code: 1 |
Next, let’s look at an example of an unsuccessful exit code with a message.
Example of Error Message Exit Code
We can explore setting a string message as an exit code.
Recall, setting a string message as an exit code will indicate an unsuccessful exit, setting an exit code of one and reporting the string message on standard error (stderr).
We can update the previous example to set a string message when calling sys.exit().
1 2 3 |
... # exit unsuccessfully with a message exit('Something bad happened') |
The updated task() function with this change is listed below.
1 2 3 4 5 6 |
# function executed in a child process def task(): # block for a moment sleep(1) # exit unsuccessfully with a message exit('Something bad happened') |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# SuperFastPython.com # example of an unsuccessful exit code message from time import sleep from multiprocessing import Process from sys import exit # function executed in a child process def task(): # block for a moment sleep(1) # exit unsuccessfully with a message exit('Something bad happened') # protect the entry point if __name__ == '__main__': # configure a new process child = Process(target=task) # start the child process child.start() # wait for the child process to finish child.join() # check the exit code for the child process code = child.exitcode print(f'Child exit code: {code}') |
Running the example first creates and starts the child process.
The main process then blocks until the child process terminates.
The child process sleeps for one second, then exits with an exit code of a string message, indicating an unsuccessful exit.
The child process terminates, reports the string message to standard error, then the main process continues on.
The main process then retrieves the exit code from the child process and reports the value.
In this case, we can see that the message was reported automatically, and that the exit code has the value of one, indicating an unsuccessful exit.
1 2 |
Something bad happened Child exit code: 1 |
Free Python Multiprocessing Course
Download your FREE multiprocessing PDF cheat sheet and get BONUS access to my free 7-day crash course on the multiprocessing API.
Discover how to use the Python multiprocessing module including how to create and start child processes and how to use a mutex locks and semaphores.
Automatic Exit Codes
This section provides examples of automatically setting an exit code when terminating a process.
Automatic Exit Code On Normal Exit
In this case we can explore the exit code set automatically when a Python process exits normally.
Recall that the exit code is set to zero indicating a successful exit when a Python process exits normally.
We can achieve this by updating the previous example to remove the call to sys.exit() from the task() function executed in a child process.
The updated task() function with this change is listed below.
1 2 3 4 |
# function executed in a child process def task(): # block for a moment sleep(1) |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# SuperFastPython.com # example of a normal successful exit for a process from time import sleep from multiprocessing import Process from sys import exit # function executed in a child process def task(): # block for a moment sleep(1) # protect the entry point if __name__ == '__main__': # configure a new process child = Process(target=task) # start the child process child.start() # wait for the child process to finish child.join() # check the exit code for the child process code = child.exitcode print(f'Child exit code: {code}') |
Running the example first creates and starts the child process.
The main process then blocks until the child process terminates.
The child process sleeps for one second, then exits normally with no explicit exit code
The child process terminates then the main process continues on. It retrieves the exit code from the child process and reports the value.
In this case, we can see it has the value zero indicating a successful exit was set automatically when the child process exited normally.
1 |
Child exit code: 0 |
Automatic Exit Code On Exception
In this case we can explore the exit code set automatically when a Python process exits with an exception.
Recall that the exit code is set to one indicating an unsuccessful exit when a Python process exits with an exception.
We can achieve this by updating the previous example to raise an exception in the function executed by the child process.
1 2 3 |
... # raise an exception raise Exception('Something bad happened') |
The updated task() function with this change is listed below.
1 2 3 4 5 6 |
# function executed in a child process def task(): # block for a moment sleep(1) # raise an exception raise Exception('Something bad happened') |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# SuperFastPython.com # example of a unsuccessful exit for exiting with exception from time import sleep from multiprocessing import Process from sys import exit # function executed in a child process def task(): # block for a moment sleep(1) # raise an exception raise Exception('Something bad happened') # protect the entry point if __name__ == '__main__': # configure a new process child = Process(target=task) # start the child process child.start() # wait for the child process to finish child.join() # check the exit code for the child process code = child.exitcode print(f'Child exit code: {code}') |
Running the example first creates and starts the child process.
The main process then blocks until the child process terminates.
The child process sleeps for one second, then exits by raising an exception.
The exception stack trace is reported to standard error, the default behavior for handling an exception in a child process
The child process terminates then the main process continues on. It retrieves the exit code from the child process and reports the value.
In this case, we can see it has the value zero indicating an unsuccessful exit was set automatically when the child process exited with an exception.
1 2 3 4 5 |
Process Process-1: Traceback (most recent call last): ... Exception: Something bad happened Child exit code: 1 |
Overwhelmed by the python concurrency APIs?
Find relief, download my FREE Python Concurrency Mind Maps
Further Reading
This section provides additional resources that you may find helpful.
Python Multiprocessing Books
- Python Multiprocessing Jump-Start, Jason Brownlee (my book!)
- Multiprocessing API Interview Questions
- Multiprocessing API Cheat Sheet
I would also recommend specific chapters in the books:
- Effective Python, Brett Slatkin, 2019.
- See: Chapter 7: Concurrency and Parallelism
- High Performance Python, Ian Ozsvald and Micha Gorelick, 2020.
- See: Chapter 9: The multiprocessing Module
- Python in a Nutshell, Alex Martelli, et al., 2017.
- See: Chapter: 14: Threads and Processes
Guides
- Python Multiprocessing: The Complete Guide
- Python Multiprocessing Pool: The Complete Guide
- Python ProcessPoolExecutor: The Complete Guide
APIs
References
Takeaways
You now know how to get and set exit codes for processes in Python.
Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.
Photo by David Maginley on Unsplash
Do you have any questions?