Research on pthread_cleanup_push () and pthread_cleanup_pop () of sub-threads in Linux, pthreadcleanuppush

Source: Internet
Author: User

Research on pthread_cleanup_push () and pthread_cleanup_pop () of sub-threads in Linux, pthreadcleanuppush

Some cleanup work may be performed before the thread exits, but this part of the code will not be placed in the main part of the thread, and one or more threads need to be mounted as "cleaners" to do this part. This pair of brothers is required:

#include<pthread.h>void pthread_cleanup_push(void (*rtn)(void *), void *arg);void pthread_cleanup_pop(int execute);

 

Apparently, pthread_cleanup_push () is the hook cleaning function, and its return value type is void. There are two entry parameters. The first parameter is the cleaning function pointer, the second parameter is the typeless pointer passed to the cleaning function.

Another brother, pthread_cleanup_pop (), is used to trigger the cleanup function in the reverse order. If its entry parameter execute is 0, the corresponding cleaning function is not actually executed.

For example:

 

1 /************************************** * ************************** 2 # File Name: thread_cleanup3.c 3 # Author: lintex9527 4 # E-Mail: lintex9527@yeah.net 5 # Created Time: Sat 22 Aug 2015 03:25:09 pm hkt 6 # Purpose: test the trigger sequence of the cleanup function, and whether it is executed or not. 7 # Outline: 8 # Usage: 9 # -------------------------------------------------- 10 # Result: 11 # -------------------------------------------- 12 ************************************ * ****************************/13 # include <stdio. h> 14 # include <stdlib. h> 15 # include <pthread. h> 16 17/* The parameter struct passed by the thread to the cleanup function */18 struct argtype {19 int a, B; 20 int result; 21}; 22 23 void print_argtype (con St char * str, struct argtype * p) 24 {25 printf ("% s \ n", str); 26 printf ("a = % d, B = % d \ n ", p-> a, p-> B); 27 printf (" result = % d \ n ", p-> result ); 28} 29 30/* for thread 1 */31 struct argtype entity1 = {32. a = 50, 33. B = 5, 34. result = 11 35}; 36 37/* below are 3 cleanup functions */38 void cleanup_add (void * arg) 39 {40 struct argtype * p = (struct argtype *) arg; 41 p-> result = p-> a + p-> B; 42 print_argtype ("Cleanup [add]", p); 43 // pthread_exit (void *) p-> result); 44} 45 46 void cleanup_minus (void * arg) 47 {48 struct argtype * p = (struct argtype *) arg; 49 p-> result = p-> a-p-> B; 50 print_argtype ("cleanup [minus]", p); 51 // pthread_exit (void *) p-> result); 52} 53 54 55 void cleanup_times (void * arg) 56 {57 struct argtype * p = (struct argtype *) arg; 58 p-> result = p-> a * p-> B; 59 print_argtype ("cl Eanup [times] ", p); 60 // pthread_exit (void *) p-> result); 61} 62 63/* subthread 1 function, temporarily changed the member value in the entity1 struct, and checked the cleanup function execution point */64 void * thr0000fun (void * arg) 65 {66 printf ("Now thread1 [% lu] start: \ n ", pthread_self (); 67 68 pthread_cleanup_push (cleanup_times, (void *) & entity1); // cleanup_times 69 entity1.a = 20; 70 entity1. B = 2; 71 pthread_cleanup_push (cleanup_minus, (void *) & entity1); // cleanup_minus 72 pth Read_cleanup_push (cleanup_add, (void *) & entity1); // cleanup_add 73 pthread_cleanup_pop (3); // cleanup_add 74 75 entity1.a = 30; 76 entity1. B = 3; 77 percent (1); // cleanup_minus 78 79 entity1.a = 40; 80 entity1. B = 4; 81 pthread_cleanup_pop (1); // cleanup_times 82 83 entity1.a = 80; 84 entity1. B = 8; 85 pthread_exit (void *) entity1.result); 86} 87 88 89 int main (void) 90 {91 int err; 92 pthread_t tid1; 93 void * tret; 94 95 err = pthread_create (& tid1, NULL, thr1_fun, NULL); 96 err = pthread_join (tid1, & tret ); 97 if (err! = 0) 98 {99 perror ("pthread_join"); 100 return-1; 101} 102 103 printf ("In main get result [% d] from thread % lu \ n", tret, tid1); 104 print_argtype ("main:", & entity1 ); 105 106 return 0; 107}

 

 

Execution result:

$ ./thread_cleanup3.exe Now thread1 [140090204903168] start:cleanup [add]    a = 20, b = 2    result = 22cleanup [minus]    a = 30, b = 3    result = 27cleanup [times]    a = 40, b = 4    result = 160In main get result [160] from thread 140090204903168main:    a = 80, b = 8    result = 160

 

Sequential Test

In this example, I set execute in pthread_cleanup_pop (int execute) to a non-zero value and test the call sequence of the three cleanup functions,

The registration order is cleanup_times --> cleanup_minus --> cleanup_add

The call order is: cleanup_add --> cleanup_minus --> cleanup_times

It is indeed called in the reverse order.

Execute point test

To test the execution point of each cleanup function, I modified the and B fields of the struct entity1 before every pthread_cleanup_pop. After comparison, we found that each pthread_cleanup_push () and pthread_cleanup_pop () form a pairs because they are macro-based. pthread_cleanup_push () contains a "{", while pthread_cleanup_pop () it contains a "}" and the previous correspondence, so they must appear in pairs, otherwise the code will not pass the compilation. After inspection and comparison, it is found that although each pairs is nested in the code form, their execution is not nested with each other. That is, the cleanup_times () command is run on the outermost cleanup_times () and cleanup_times () is called recursively ().

Therefore, code from pthread_cleanup_push (cleanup_minus, xxx) to pthread_cleanupo_pop (yyy) (corresponding to cleanup_minus) is blocked when processing the outermost cleanup_times.

While cleanup_minus () is being processed, code from pthread_cleanup_push (cleanup_add, xxx) to pthread_cleanup_pop (yyy) (corresponding to cleanup_add) is blocked.

Because the pop order is the opposite of the push order, execute cleanup_add --> cleanup_minus --> cleanup_times from the first pop order.

 

But why is the parameter cleanup_xxx executed every time different? Where did the change begin?

Is from the thread function entry to the bottom, until the pthread_cleanup_pop () part of the parameter is valid for the current cleanup_xxx () function. The statement below pthread_cleanup_pop () currently takes effect for the next pop () function.

As shown in the figure below:

The indicator lines on the left represent the resource zones accessible to each push-in stack cleaning function;

The double arrow lines on the right represent the push/pop pairs. Although the code is nested, the function execution is not nested.

According to the analysis,

Entity1.a, entity1. B passed to the cleanup_add () function. The values are 20, 2;

Entity1.a, entity1. B passed to the cleanup_minus () function. The value is 30, 3;

Entity1.a, entity1. B passed to the cleanup_times () function. The values are 40, 4;

The value of entity1.a and entity1. B that can be accessed in main thread is 80 and 8. At that time, the cleanup_xxx () function was not cleared to access the entity1 struct.

 

In addition, I added the pthread_exit () function to the cleanup function. What will happen? For example, to cancel the comments before pthread_exit () in the cleanup_times () function, compile the running result as follows:

$ ./thread_cleanup3.exe Now thread1 [140415830189824] start:now cleanup_add.cleanup [add]    a = 20, b = 2    result = 22now cleanup_minus.cleanup [minus]    a = 30, b = 3    result = 27now cleanup_times.cleanup [times]    a = 40, b = 4    result = 160In main get result [160] from thread 140415830189824main:    a = 40, b = 4    result = 160

Before comparison, we found that the values of a and B in main thread are 40 and 4, which is related to the exit point of the sub-thread. The sub-thread did not go to the following step:

Entity1.a = 40; entity1. B = 4; printf ("now cleanup_times. \ n"); pthread_cleanup_pop (1); // cleanup_times
------------------------------------------------------------------- // The following code is not executed:
Entity1.a = 80; entity1. B = 8; printf ("thread 1 is exit... \ n"); pthread_exit (void *) entity1.result );

It indicates that when pthread_exit () is used in advance, the resources accessed by each function are more limited.

However, adding pthread_exit () to two or more cleanup functions will cause the thread to continuously call the cleanup function and enter the dead state.

In summary, do not add pthread_exit () to the cleanup function ().

 

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.