Race conditions in python

Race Condition With a Shared Variable in Python

You can fix race conditions with shared variables using a mutual exclusion lock.

In this tutorial you will discover race conditions with shared variables in Python.

Race Condition with a Shared Variable

A race condition is a bug in concurrency programming.

It is a failure case where the behavior of the program is dependent upon the order of execution by two or more threads. This means, the behavior of the program will not be predictable, possibly changing each time it is run.

There are many types of race conditions, although a common type of race condition is when two or more threads attempt to change the same data variable.

NOTE: Race conditions are a real problem in Python when using threads, even in the presence of the global interpreter lock (GIL). The refrain that there are no race conditions in Python because of the GIL is dangerously wrong.

For example, one thread may be adding values to a variable, while another thread is subtracting values from the same variable.

Let’s call them an adder thread and a subtractor thread.

At some point, the operating system may context switch from the adding thread to the subtracting thread in the middle of updating the variable. Perhaps right at the point where it was about to write an updated value with an addition, say from the current value of 100 to the new value of 110.

You may recall that the operating system controls what threads execute and when, and that a context switch refers to pausing the execution of a thread and storing its state, while unpausing another thread and restoring its state.

You may also notice that the adding or subtracting from the variable is composed of at least three steps:

  1. Read the current value of the variable.
  2. Calculate a new value for the variable.
  3. Write a new value for the variable.

A context switch between threads may occur at any point in this task.

Back to our threads. The subtracting thread runs and reads the current value as 100 and reduces the value from 100 to 90.

This subtraction is performed as per normal and the variable value is now 90.

The operating system context switches back to the adding thread and it picks up where it left off writing the value 110.

This means that in this case, one subtraction operation was lost and the shared balance variable has an inconsistent value. A race condition.

Next, let’s look at how we might fix this race condition.

Run your loops using all CPUs, download my FREE book to learn how.

Fix a Race Condition with a Shared Variable

There are many ways to fix a race condition between two or more threads with a shared variable.

The approach taken may depend on the specifics of the application.

Nevertheless, a common approach is to protect the critical section of code. This may be achieved with a mutual exclusion lock, sometimes simply called a mutex.

If you are new to the mutex lock, you can learn more here:

You may recall that a critical section of code is code that may be executed by two or more threads concurrently and may be at risk of a race condition.

Updating a variable shared between threads is an example of a critical section of code.

A critical section can be protected by a mutex lock which will ensure that one and only one thread can access the variable at a time.

This can be achieved by first creating a threading.Lock instance.

Источник

How to Fix a Race Condition With Timing in Python

You can fix a race condition based on timing using a threading.Event.

In this tutorial you will discover how to identify and fix a timing-based race condition in Python.

Race Condition with Timing

A race condition is a bug in concurrency programming.

It is a failure case where the behavior of the program is dependent upon the order of execution by two or more threads. This means, the behavior of the program will not be predictable, possibly changing each time it is run.

There are many types of race conditions, although a common type of race condition is when two threads attempt to coordinate their behavior.

Note: Race conditions are a real problem in Python when using threads, even in the presence of the global interpreter lock (GIL). The refrain that there are no race conditions in Python because of the GIL is dangerously wrong.

For example, consider the case of the use of a threading.Condition used by two threads to coordinate their behavior.

If you are new to a condition object, you can learn more here:

One thread may wait on the threading.Condition to be notified of some state change within the application via the wait function.

Recall that when using a threading.Condition, you must acquire the condition before you can call wait() or notify(), then release it once you are done. This is easily achieved using the context manager.

Another thread may perform some change within the application and alert the waiting thread via the condition with the notify() function.

This is an example of coordinated behavior between two threads where one thread signals another thread.

For the behavior to work as intended, the notification from the second thread must be sent after the first thread has started waiting. If the first thread calls wait() after the second thread calls notify(), then it will not be notified and will wait forever.

This may happen if there is a context switch by the operating system that allows the second thread that calls notify() to run before the first thread that calls wait() to run.

You may recall that the operating system controls what threads execute and when, and that a context switch refers to pausing the execution of a thread and storing its state, while unpausing another thread and restoring its state.

Now that we are familiar with a race condition due to timing, let’s look at how we might fix it.

Run your loops using all CPUs, download my FREE book to learn how.

Fix a Race Condition with Timing

There are many ways to fix a race condition between two or more threads based on timing.

The approach taken may depend on the specifics of the application.

Nevertheless, one common approach is to have the waiting threads signal that they are ready before the notifying thread starts its work and calls notify.

This can be achieved with a threading.Event, which is like a thread-safe boolean flag variable.

If you are not familiar with the threading.Event, you can learn more here:

A shared threading.Event object can be created.

Источник

Читайте также:  Java compiled class file
Оцените статью