Linux implementation of POSIX thread cancellation point (zz)

Source: Internet
Author: User
In a very good article, I have thoroughly analyzed the concept and implementation method of the POSIX thread's cancellation point (Cancellation point), ZZ.

The following ZZ from: http://blog.solrex.cn/articles/linux-implementation-of-posix-thread-cancellation-points.html

Abstract:

This article describes how to implement POSIX thread cancellation points in the Linux system and how to avoid the thread deadlock caused by the next Linux pthread_cancel function.

Directory:

1. A small example of thread deadlock caused by pthread_cancel
2. cancelingpoint)
3. Cancellation type)
4. Implementation of cancellation points in Linux
5. Explanation of the deadlock in the example function
6. How to avoid deadlocks
7. Conclusion
8. References

1. A small example of thread deadlock caused by pthread_cancel

The following is a small example of thread deadlock caused by Linux. This instance program only uses the condition variable and mutex for a simple thread synchronization, thread0
First start, lock mutex, and then call pthread_cond_wait. It puts the thread TID [0] on the list of threads waiting for the condition
Mutex unlock. Wait 10 seconds after thread1 starts. At this time, pthread_cond_wait should have unlocked mutex.
The TID [1] thread locks the mutex, then broadcasts the signal to wake up all the waiting threads of the cond wait condition, and then unlocks the mutex. When mutex
After unlocking, The pthread_cond_wait function of the TID [0] thread re-locks the mutex and returns the result. Finally, tid [0] re-locks the mutex
To unlock.
[Code: C]
1 # include <pthread. h>
2
3 pthread_mutex_t mutex = pthread_mutex_initializer;
4 pthread_cond_t cond = pthread_cond_initializer;
5
6 void * thread0 (void * Arg)
7 {
8 pthread_mutex_lock (& mutex );
9 pthread_cond_wait (& cond, & mutex );
10 pthread_mutex_unlock (& mutex );
11 pthread_exit (null );
12}
13
14 void * thread1 (void * Arg)
15 {
16 sleep (10 );
17 pthread_mutex_lock (& mutex );
18 pthread_cond_broadcast (& Cond );
19 pthread_mutex_unlock (& mutex );
20 pthread_exit (null );
21}

22 int main ()
23 {
24 pthread_t TID [2];
25 if (pthread_create (& tid [0], null, & thread0, null )! = 0 ){
26 exit (1 );
27}
28 If (pthread_create (& tid [1], null, & thread1, null )! = 0 ){
29 exit (1 );
30}
31 sleep (5 );
32 pthread_cancel (TID [0]);
33
34 pthread_join (TID [0], null );
35 pthread_join (TID [1], null );
36
37 pthread_mutex_destroy (& mutex );
38 pthread_cond_destroy (& Cond );
39 return 0;
40} [/Code]

It seems that there is no problem, but the main function calls a pthread_cancel to cancel TID [0].
Thread. The above program will not be terminated when it is run after compilation. It looks like pthread_cancel is not executed when TID [0] is canceled.
Pthread_mutex_unlock function, so that the mutex will be locked forever, And the thread TID [1] will be stuck in endless waiting. Is that true?

2. cancelingpoint)

Note that pthread_cancel
The call does not wait for the thread to terminate. It only initiates a request. The thread continues running after the pthread_cancel request is canceled until it reaches
A cancellation point ). The cancellation point is a location where the thread checks whether the request is canceled and performs the action according to the request. Pthread_cancel
Manual said that the following POSIX thread functions are cancellation points:
[Code]
Pthread_join (3)
Pthread_cond_wait (3)
Pthread_cond_timedwait (3)
Pthread_testcancel (3)
Sem_wait (3)
Sigwait (3)
[/Code]
In the middle, we can find that pthread_cond_wait is one of the cancellation points.

However, what is confusing is that all the introduction of cancellation points
The article only says that when the thread is canceled, it will continue to run until the cancellation point and the cancellation action will take place. However, we noticed that in the above example, the main
The function has been sleep for 5 seconds, so when pthread_cancel is called, thread0 is actually running
Pthread_cond_wait?

If thread0 runs
Pthread_cond_wait, as stated above, it should continue to run to the next cancellation point and the cancellation action will take place, and there will be no cancellation point later, so thread0
It should be run to pthread_exit and end, then mutex will be unlocked, so there should be no deadlock.

3. Cancellation type)

We will find that the function is cancellation.
Points. This method is confusing. Because function execution is a time process, not a time point. Actually, the real cancellation points
In these functions, the cancellation type is modified to phread_cancel_asynchronous and
Pthread_cancel_deferred.

POSIX
There are two types of cancellation, one is delay cancellation (pthread_cancel_deferred), which is the default cancellation type of the system, that is, before the thread reaches the cancellation point, there will be no real
The other is asynchronous cancellation (phread_cancel_asynchronous). When asynchronous cancellation is used, the thread can be canceled at any time.

4. Implementation of cancellation points in Linux

Next we will see how Linux implements the cancellation. (In fact, it should be accurate to the GNU cancellation implementation, because the pthread library is implemented in glibc .) The pthread library we use in Linux is actually replaced with nptl and included in the glibc library.

Take pthread_cond_wait as an example, in glibc-2.6/nptl/pthread_cond_wait.c:
[Code: C]
145/* enable asynchronous cancellation. required by the standard .*/
146 cbuffer. oldtype = _ pthread_enable_asynccancel ();
147
148/* Wait Until woken by signal or broadcast .*/
149 lll_futex_wait (& cond->__ data. _ futex, futex_val );
150
151/* disable asynchronous cancellation .*/
152 _ pthread_disable_asynccancel (cbuffer. oldtype); [/Code]

We can see that before the thread enters the waiting state, pthread_cond_wait
First, set the thread cancellation type to asynchronous cancellation (_ pthread_enable_asynccancel). When the thread is awakened, the thread cancellation type is changed back to delay cancellation.
_ Pthread_disable_asynccancel.

This means that all cancellation requests received before _ pthread_enable_asynccancel will wait
_ Pthread_enable_asynccancel
Previously received requests will be processed before _ pthread_disable_asynccancel, so the real Cancellation
Point is a period of time between these two points.

5. Explanation of the deadlock in the example function

Before calling pthread_cancel in the main function, thread0 enters the pthread_cond_wait function and adds itself to the list of threads waiting for the condition (lll_futex_wait ). This can be verified by GDB setting breakpoints on each function.

When pthread_cancel is called, The TID [0] thread is still waiting, and the cancellation request occurs in
_ Pthread_disable_asynccancel. But pthread_cond_wait
To register a thread cleanup Program (glibc-2.6/nptl/pthread_cond_wait.c ):
[Code: C]
126/* Before we block we enable cancellation. Therefore we have
127 install a cancellation handler .*/
128 _ pthread_cleanup_push (& buffer, _ condvar_cleanup, & cbuffer); [/Code]

So what does the thread cleanup program _ condvar_cleanup do? We can note that at the end of its implementation (glibc-2.6/nptl/pthread_cond_wait.c ):
[Code: C]
85/* Get the mutex before returning unless asynchronous Cancellation
86 is in effect .*/
87 _ pthread_mutex_cond_lock (cbuffer-> mutex );
88} [/Code]

Oh, __condvar_cleanup re-locks the mutex at the end. At this time, thread1 is still sleep (10). When it wakes up, mutex will be locked forever, Which is why thread1 is stuck in endless congestion.

6. How to avoid deadlocks

Since the policy used by the thread cleanup function pthread_cleanup_push is Filo, we can register a thread handler before the pthread_cond_wait function:
[Code: C]
Void cleanup (void * Arg)
{
Pthread_mutex_unlock (& mutex );
}
Void * thread0 (void * Arg)
{
Pthread_cleanup_push (cleanup, null); // thread cleanup Handler
Pthread_mutex_lock (& mutex );
Pthread_cond_wait (& cond, & mutex );
Pthread_mutex_unlock (& mutex );
Pthread_cleanup_pop (0 );
Pthread_exit (null );
} [/Code]

In this way, when the thread is canceled, execute the thread cleanup function _ condvar_cleanup registered in pthread_cond_wait, lock the mutex, and then execute the thread cleanup function registered in thread0 to unlock the mutex. This avoids deadlocks.

7. Conclusion

Thread Synchronization under multiple threads has always been a headache. POSIX introduces cancellation to avoid immediate cancellation of resource occupation caused by programs
The points concept is a very good design, but the improper use of pthread_cancel still causes thread synchronization problems. Understand POSIX thread cancellation points
The implementation in Linux is more helpful to understand its mechanism and facilitate better application of this mechanism.

8. References

[1] W. Richard Steven S, Stephen A. Rago: Advanced Programming in the Unix environment, 2nd edition.
[2] Linux manpage

Link: http://blog.solrex.cn/go/623339.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.