Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this noncompliant code example, the worker thread is doing something as simple as swapping a and b repeatedly.

This code uses one lock. The global_lock mutex ensures that the worker thread and main thread do not collide in accessing the a and b variables.

The worker thread repeatedly exchanges the values of a and b until it is canceled by the main thread. The main thread then prints out the current values of a and b. Ideally, one should be 5, and the other should be 10.

...

However, this program is subject to a race condition because an asynchronous cancel can happen at any time. If the worker thread is canceled while the global_lock mutex is held, it is never actually released. In this case, the main thread will wait forever trying to acquire the global_lock, and the program will deadlock.

It is also possible that the main thread cancels the worker thread before it has invoked pthread_setcanceltype(). If this happens, the cancelation will be delayed until the worker thread calls pthread_setcanceltype().

Noncompliant Code Example

In this example, the worker thread arranges to release the global_lock mutex if it gets interrupted.

...

The global variables are still subject to a race condition because an asynchronous cancel can happen at any time. For instance, the worker thread could be canceled just before the last line (a = c) and thereby lose the old value of b. Consequently, the main thread might print that a and b have the same value.

The program is still subject to the race condition where the main thread cancels the worker thread before it has invoked pthread_setcanceltype(). If this happens, the cancelation will be delayed until the worker thread calls pthread_setcanceltype().

Furthermore, though less likely, the program can still deadlock if the worker thread gets canceled after the global_lock is acquired but before pthread_cleanup_push() is invoked. In this case, the worker thread is canceled while holding global_lock, and the program will deadlock.

...

Because this code limits cancelation of the worker thread to the end of the while loop, the worker thread can preserve the data invariant that a != b. Consequently, the program might print that a is 5 and b is 10 or that a is 10 and b is 5, but they will always be revealed to have different values when the worker thread is canceled.

The other race conditions that plague the noncompliant code examples are not possible here. Because the worker thread does not modify its cancel type, it cannot be canceled before being improperly initialized. And because it cannot be canceled while the global_lock mutex is held, there is no possibility of deadlock, and the worker thread does not need to register any cleanup handlers.

...