<Unix environment advanced programming (second edition)> thread learning P287-P297
# Include <pthread. h> // create thread int pthread_create (pthread_t * restrict TIDP, const pthread_attr_t * restrict ATTR, void * (* start_rtn) (void *), void * restrict Arg ); // The thread terminates void pthread_exit (void * rval_ptr); // The thread automatically exits int pthread_join (pthread_t tid, void ** rval_ptr); // other threads block itself, wait for TID to exit // The thread to clear void pthread_cleanup_push (void (* RTN) (void *), void * Arg); void pthread_cleanup_pop (INT execute );
Note:
1. Thread Creation
The Return Value of the pthread_create () function is 0, indicating that the creation is successful, and the thread ID is stored in the TIDP; if the failure occurs, the return value is non-zero and needs to be processed by the user. The errno value is not modified.
2. Thread termination
A. Calling exit, _ exit, and _ exit by any thread will lead to the termination of the entire process;
B. There are three ways to exit a single thread:
1> return is used in start_rtn (), and the return value is the thread exit code;
2> it is canceled by other threads of the same process using pthread_cancel;
3> the thread itself calls pthread_exit ();
Note: The pthread_join (pthread_t tid, void ** rval_ptr) function blocks the calling thread until the TID thread terminates and exits through the above three methods, and return/pthread_exit () the corresponding thread exit code rval_ptr is set, and the thread that pthread_cancel () is canceled sets the exit code to pthread_canceled.
3. Thread cleanupProgram(Thread cleanup handler)
3. A> pthread_cleanup_push () and pthread_cleanup_pop () are both macro definitions implemented in <pthread. h>. The specific implementation is as follows:
Pthread_cleanup_push and pthread_cleanup_pop are macros and must always be used in matching pairs at the same nesting level of braces. */# define pthread_cleanup_push (routine, ARG) \ do {\__ pthread_cleanup_class _ clframe (routine, ARG)/* remove a cleanup handler installed by the matching pthread_cleanup_push. if execute is non-zero, the handler function is called. */# define pthread_cleanup_pop (execute) \ _ clframe. _ setdoit (execute); \} while (0)
It can be seen that the {/} in Push/pop is one-to-one, so pthread_cleanup_push/POP () should also be one-to-one, otherwise compilation errors will occur.
3. B> when the thread executes one of the following operations, the cleanup function is called. thread_cleanup_push is implemented by the stack structure. Pay attention to the order in which the program is called.
1: When pthread_exit () is called, direct return does not start to clean up the function;
2: cancel the pthread_cancel () request accordingly;
3: When pthread_cleanup_pop () is called using the non-zero execute parameter;
Note that the pthread_cleanup_pop () parameter varies with the position of the statement.
Check thisCodeInstance. Note that the return or pthread_exit () locations are different, resulting in changes in the effect of different parameters of pthread_cleanup_pop.
# Include <pthread. h> void testpointersize () {void * tret; printf ("size of pointer in x86-64: % d \ n", sizeof (tret); // result is 8 in x86-64. // which is 4 in x86-32.printf ("size of int in x86-64: % d \ n", sizeof (INT); // result is 4 in x86-64. // which is also 4 in x86-32 .} void cleanup (void * Arg) {printf ("cleanup: % s \ n", (char *) Arg);} void * thr_fn1 (void * Arg) {printf ("thread 1 start \ n"); pthread_cleanup_push (cleanup ," Thread 1 first handler "); pthread_cleanup_push (cleanup," thread 1 second handler "); If (ARG) Return (void *) 1); // Arg! = 0, return here. // return here will not triger any cleanup. pthread_cleanup_pop (0); pthread_cleanup_pop (1); Return (void *) 2); // will not run this} void * thr_fn2 (void * Arg) {printf ("thread 2 start \ n"); pthread_cleanup_push (cleanup, "thread 2 first handler"); pthread_cleanup_push (cleanup, "thread 2 second handler "); pthread_cleanup_pop (0); pthread_cleanup_pop (1); Return (void *) 2); // return here can triger cleanup second handler;} void * thr_fn3 (void * Arg) {printf ("thread 3 Start \ n"); pthread_cleanup_push (cleanup, "thread 3 first handler"); pthread_cleanup_push (cleanup, "thread 3 second handler"); If (ARG) pthread_exit (void *) 3); // pthread_exit () here will triger both cleanup first & Second handler. pthread_cleanup_pop (1); pthread_cleanup_pop (0); pthread_exit (void *) 3); // wont run this} void * thr_fn4 (void * Arg) {printf ("thread 4 start \ n"); pthread_cleanup_push (cleanup, "thread 4 first handler"); pthread_cleanup_push (cleanup, "thread 4 second handler "); pthread_cleanup_pop (1); pthread_cleanup_pop (0); pthread_exit (void *) 4); // pthread_exit () here will triger cleanup second handler .} int main (void) {testpointersize (); int err; pthread_t tid1, tid2, tid3, tid4; void * tret; err = pthread_create (& tid1, null, thr_fn1, (void *) 1); err = pthread_join (tid1, & tret); printf ("thread 1 exit code % d \ n", (INT) tret ); err = pthread_create (& tid2, null, thr_fn2, (void *) 2); err = pthread_join (tid2, & tret ); printf ("thread 2 exit code % d \ n", (INT) tret); err = pthread_create (& tid3, null, thr_fn3, (void *) 3 ); err = pthread_join (tid3, & tret); printf ("thread 3 Exit code % d \ n", (INT) tret); err = pthread_create (& tid4, null, thr_fn4, (void *) 4); err = pthread_join (tid4, & tret); printf ("thread 4 exit code % d \ n", (INT) tret );}
Running result:
[Root @ Hello testdata] #. /test size of pointer in x86-64: 8 size of int in x86-64: 4 thread 1 startthread 1 exit code 1 thread 2 startcleanup: thread 2 first handlerthread 2 exit code 2 thread 3 startcleanup: thread 3 second handlercleanup: thread 3 first handlerthread 3 Exit code 3 thread 4 startcleanup: thread 4 second handlerthread 4 exit code 4
The test procedure is summarized as follows:
1> the return between push and Pop will prevent the cleaning program from being triggered;
2> return after pop. The pop parameter determines whether to trigger the cleaning program. The non-zero parameter is triggered and the zero parameter is not triggered;
3>Pthread_exit () between push and Pop will trigger all cleanup functions;
4> when pthread_exit () is located after pop, the pop parameter determines whether to trigger the cleanup program;
In fact, the above four situations only test and verify the three conditions described in Article 3. B to deepen understanding.
References:
1. POSIX Thread Programming Guide (4)
2. <Unix environment advanced programming (version 2nd)> P295-296 Program
3. Details about pthread_cleanup_push ()/pthread_cleanup_pop ()
4. Vim column editing instance (Mark record) in Linux)