Starting and Stopping Python Threads With Events in Python Threading Module.

by xanthium-enterprises in Circuits > Software

11293 Views, 1 Favorites, 0 Comments

Starting and Stopping Python Threads With Events in Python Threading Module.

Creating and sharing data between Python Threads using data structures like queue, locks & events

In this instructable, we'll walk through how to use Python's threading module to start and stop threads using events. Threads are a way to execute multiple tasks concurrently within a single process

Multithreading is a powerful concept in Python that allows developers to execute multiple tasks concurrently, improving performance and responsiveness in applications. The threading module in Python provides a way to work with threads efficiently. One common requirement in multithreaded applications is the ability to start and stop threads gracefully. In this article, we'll explore how to achieve this using events in the Python threading module.

Understanding Python Threading Module

Python's threading module allows developers to create and manage threads in their applications. A thread represents a separate flow of execution within a process. By leveraging threads, developers can perform tasks concurrently, utilizing the available CPU resources more effectively.

Events in Threading

Events are synchronization primitives in Python that allow threads to communicate with each other. An event is an object that can be set to a state of "set" or "unset". Threads can wait for an event to become set or unset before proceeding with their execution. Events are commonly used for signaling between threads, such as to indicate when a certain condition has been met.


Original Article and Source Codes


  1. Starting and Stopping Python Threads with Events in Python Threading Module
  2. Source Codes



Supplies

Python-logo-notext.svg.png
  • Python installed on your system (Python 3.x recommended)
  • Text editors
  • Source codes

What Are Events in Python Threading

In Python threading, an "event" is a synchronization primitive used to coordinate between multiple threads. It allows one or more threads to wait until a certain condition is set or cleared by other threads.


The threading.Event class in Python provides a simple way to communicate between threads using a flag that can be set or cleared. Here's a brief overview of its main methods:


  1. Event() - This creates a new event object with an initial flag value of False.
  2. set()    - Sets the flag of the event to True, allowing threads waiting for this event to proceed.
  3. clear()  - Resets the flag of the event to False.
  4. is_set() - Returns True if the flag is set, False otherwise.

Creating and Using an Event in Python

using-events-python-threading.jpg

Creating an event in Python is quite straightforward, thanks to the threading module. Events are synchronization primitives that allow one or more threads to wait until a certain condition is satisfied. Here's how you can create an event in Python

Start by importing the threading module, which provides support for working with threads and synchronization primitives like events.

import threading

Instantiate an event object using the Event class provided by the threading module.

Once the event object is created, you can use it to coordinate threads. The main operations on an event are set(), clear(), and wait().

  • set(): This sets the event, allowing one or more threads waiting for it to proceed.
  • clear(): This clears the event, making it wait for the event to be set again.
  • wait(timeout=None): This blocks the calling thread until the event is set. If a timeout is specified, it blocks for at most the number of seconds specified by the timeout parameter
# Setting the event
event.set()

# Clearing the event
event.clear()

# Waiting for the event to be set
event.wait()



Using Event.wait() in Python Threading

setting-events-python-threads.jpg

In this demonstration, we'll employ the event.wait() method within a thread (t1) to wait until an event flag is set in the main thread, as depicted in the image above.


Here, thread t1 is awaiting the completion of an action by the main thread, such as waiting for data from an I/O device, which t1 requires. Although t1 is initiated, it remains in a waiting state until the required data becomes available.

After the main thread has finished its operation, typically upon receiving the necessary data, it sets the my_event flag using my_event.set(). Subsequently, this action notifies the my_event.wait() function within thread t1.

As a result, the my_event.wait() function exits, allowing other segments of code to execute.

Partial Code is shown below ,use full code from repo.link above

#Using event.wait() in Python threading
import ...
def function_t():
print('Entered t1 thread func')

my_event.wait(timeout = 10) # wait for the event to be set in main thread
# timeout of 10 seconds

print('Event is set,so this line gets printed')

my_event = threading.Event() # create an Event object
t1 = threading.Thread(target = function_t) # create t1 thread
t1.start() # start t1 thread
print('will set the event in 5 seconds')
time.sleep(5) #wait 5 seconds
my_event.set() #set the event after 5 seconds
t1.join()


  1. We import the necessary modules: threading for working with threads and time for adding delays.
  2. The event_thread function is defined. This function takes an event object as an argument. Within the function:
  3. It prints a message indicating that it is waiting for the event to be set.
  4. It then calls event.wait(), which blocks the thread until the event is set.
  5. Once the event is set, it prints a message indicating that the event is set, and the thread continues.
  6. We create an event object named event using threading.Event().
  7. We create a new thread thread by passing the event_thread function and the event object as arguments. The thread is then started using thread.start().
  8. We introduce a delay of 2 seconds using time.sleep(2). This simulates the main thread performing some operations before setting the event.
  9. After the delay, we set the event using event.set(). This notifies the waiting thread (thread) that the event has occurred.
  10. We wait for the thread to finish using thread.join() to ensure that the main thread doesn't exit before the thread finishes its execution.
  11. Finally, we print a message indicating that the main thread has exited.

The event_thread function waits for an event to be set before continuing its execution, while the main thread sets the event after a delay.

Output of the below code

Entered t1 thread func
will set the event in 5 seconds
Event is set,so this line gets printed
[Finished in 5.4s]




Using Python Events to Exit From an Infinite Loop Thread


In this scenario, we're utilizing Python events to exit from a thread with an infinite loop, named t1, which executes the infinite_loop_func() function. This function continuously reads data from a serial port at intervals of 1 second.

To terminate t1, you can employ the .is_set() method, enabling the main thread to set a flag, consequently prompting t1 to quit


#partial code
#
def infinite_loop_func():

print('Thread-t1:Start the loop')
while 1:

if my_event.is_set():
break

print('Thread-t1:Read from Serial Port')

time.sleep(1)
print(f'Thread-t1: my_event.is_set() = {my_event.is_set()}')

t1 = threading.Thread(target = infinite_loop_func) # create t1 thread
t1.start()
time.sleep(5) #wait 5 seconds
my_event.set() #set the event after 5 seconds

This partial code snippet demonstrates the use of a Python event to exit from a thread with an infinite loop.

The infinite_loop_func() function defines the behavior of the thread t1. Here's a breakdown of its components:

  1. print('Thread-t1:Start the loop'): This line prints a message indicating the start of the loop executed by t1.
  2. while 1:: This creates an infinite loop.
  3. if my_event.is_set():: Within the loop, this condition checks if the event my_event is set. If it is set, the loop breaks, and the thread t1 terminates.
  4. print('Thread-t1:Read from Serial Port'): This line simulates reading from a serial port, which is the primary task of t1.
  5. time.sleep(1): This statement pauses the execution of the loop for 1 second, simulating the interval between each reading from the serial port.
  6. After the loop exits, print(f'Thread-t1: my_event.is_set() = {my_event.is_set()}') prints whether the event my_event is set.

The main part of the code creates and starts the thread t1, waits for 5 seconds using time.sleep(5), and then sets the event my_event using my_event.set(). This action triggers the condition inside the loop in infinite_loop_func(), causing the loop to break and t1 to terminate.

Please note that the variable my_event should be defined as a threading.Event() object somewhere in the code for this to work properly.

Output of the code

Thread-t1:Start the loop
Thread-t1:Read from Serial Port
Thread-t1:Read from Serial Port
Thread-t1:Read from Serial Port
Thread-t1:Read from Serial Port
Thread-t1:Read from Serial Port
[Event Set in Main Thread]
Thread-t1: my_event.is_set() = True
End of the Main Thread
[Finished in 5.2s]