1. Wait for the thread to exit 1.1. Waiting for thread to exit
Threads are returned naturally from the entry point function, or the Pthread_exit () function is actively invoked to terminate the thread normally
When a thread returns from the entry point function naturally, the function return value can be obtained by other threads using the Pthread_join function.
Pthread_join prototypes are:
#include <pthread.h>
int Pthread_join (pthread_t th, void **thread_return);
1. The function is a blocking function that waits until the thread specified by the parameter th returns, similar to a wait or waitpid in a multi-process.
Thread_return is an outgoing parameter that receives the return value of a thread function. If a thread terminates by calling Pthread_exit (), the parameter in Pthread_exit () is equivalent to the natural return value, so it can be obtained by other threads with Pthread_join.
Example: Example of return value
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
void *threadfunc (void *parg)
{
int iarg = (int) parg; Convert void* to int
Sleep (Iarg);
if (Iarg < 3)
return (void *) (iarg*2);
Else
Pthread_exit (void *) (iarg*2)); As the Reaturn achieves, it can be used for normal return.
}
int main ()
{
pthread_t Thdid;
int iRet = 0;
Pthread_create (&thdid, NULL, ThreadFunc, (void *) 2); Pass parameter value is 2
Pthread_join (Thdid, (void * *) &iret); Receive the return value of a child thread
printf ("The first child thread ret is:%d\n", iRet);
Pthread_create (&thdid, NULL, ThreadFunc, (void *) 4);
Pthread_join (Thdid, (void * *) &iret);
printf ("The second child thread ret is:%d\n", iRet);
return 0;
}
2. This function also has a very important role, because the data segment is shared by multiple threads in a process, so the resources that are consumed by the exit thread will not be freed as the thread ends after a thread exits. If the th thread type does not automatically clean up the resource type, the thread itself's resources must be purged by calling Pthread_join on the other thread after the th thread exits, which is equivalent to waitpidin a multi-process program.
Example: Child Threads free space
#include <stdio.h>
#include <pthread.h>
#include <malloc.h>
void* threadfunc (void *args)
{
Char *p = (char*) malloc (10); Allocate Memory for yourself
int i = 0;
for (; i <; i++)
{
printf ("Hello,my name is wangxiao!\n");
Sleep (1);
}
Free (p); If Pthread_cancel is not called in the parent thread, you can do this here
printf ("P is freed\n");
Pthread_exit ((void*) 3);
}
int main ()
{
pthread_t Pthid;
Pthread_create (&pthid, NULL, THREADFUNC, NULL);
int i = 1;
for (; i < 5; i++)//The parent thread runs less than a child thread, and when the parent thread ends, the child thread exits if no Pthread_join function waits for the child thread to execute.
{
printf ("Hello,nice to meet you!\n");
Sleep (1);
if (i% 3 = = 0)
Pthread_cancel (Pthid); Indicates that the child thread is canceled when i%3==0, which causes the child thread to exit directly without executing the code of the purple free portion above, which is the failure to release the space. To release the variable p of the pointer type, you must use the Pthread_cleanup_push and Pthread_cleanup_pop functions to free up space, see the following example
}
int retvalue = 0;
Pthread_join (Pthid, (void**) &retvalue); Waits for the child thread to free up space and gets the return value of the child thread
printf ("Return value is:%d\n", RetValue);
return 0;
}
1.2. Cancellation of threads
Threads can also be killed by other threads, and in Linux it is said that one thread is canceled by another thread (cancel).
Thread cancellation is a thread that Cheng the cancel signal to the target line, but how to handle the cancel signal is determined by the target thread itself, either ignoring, terminating immediately, or continuing to run to Cancelation-point (the cancellation point).
Cancel point:
According to the POSIX standard, Pthread_join (), Pthread_testcancel (), pthread_cond_wait (), pthread_cond_timedwait (), sem_wait (), sigwait ( Functions such as read (), write (), and other system calls that cause blocking are cancelation-point, while other pthread functions do not cause cancelation actions. But Pthread_cancel's hand album claims that the C library function is not cancelation-point because the Linux line libraries is not well combined with the C library, but the cancel signal causes the thread to exit from the blocked system call and resets the EINTR error code. You can therefore call Pthread_testcancel () before and after a system call that needs to be cancelation-point, to achieve the target required by the POSIX standard, which is the following code snippet:
Pthread_testcancel ();
Retcode = Read (fd, buffer, length);
Pthread_testcancel ();
However, from the actual test of RedHat9.0, at least some of the blocking functions of the C library function are cancellation points, such as read (), GetChar (), and the sleep () function regardless of whether the thread is set Pthread_setcancelstate (pthread_ Cancel_disable,null), all play a role in canceling points. In short, the thread cancellation on the one hand is a thread forcibly kill another thread, from the programming point of view is not a good style, on the other hand, Linux itself in this aspect of support is not perfect, so in practical applications should be cautious use!!
int Pthread_cancel (pthread_t thread); Try not to use Linux support is not perfect
1.3. Thread Termination cleanup function
Whether it is a predictable thread termination or abnormal termination, there will be a problem of resource release, without considering the exit due to running errors, how to ensure that the thread termination can smoothly release the resources they occupy, especially the lock resources, is a must be considered to solve the problem.
The most common scenario is the use of a resource exclusive lock: The thread locks it in order to access the critical shared resource , but the thread is canceled by the outside world during the access process, or if an outage occurs, the critical resource will never be released for the locked state. Outside cancellation is not predictable, so a mechanism is needed to simplify programming for resource release.
A Pthread_cleanup_push ()/pthread_cleanup_pop () function is provided in the POSIX threading API for automatically freeing resources-from the call point of Pthread_cleanup_push () to Pthread_ The kill action in the program segment between Cleanup_pop () will execute the cleanup function specified by Pthread_cleanup_push (). The API is defined as follows:
void Pthread_cleanup_push (void (*routine) (void *), void *arg)
void Pthread_cleanup_pop (int execute)
Pthread_cleanup_push ()/pthread_cleanup_pop () using first-in, post-out stack structure management
The void routine (void *arg) function presses into the cleanup function stack when calling Pthread_cleanup_push (), and multiple calls to the Pthread_cleanup_push () will form a function chain in the cleanup function stack. When the function chain is executed, it pops up in the reverse order of the compression stack. The Execute parameter indicates whether execution to Pthread_cleanup_pop () executes the function at the same time as the cleanup function is popped, 0 means no execution, and not 0 for execution; This parameter does not affect the execution of cleanup functions at the end of an exception.
Pthread_cleanup_push ()/pthread_cleanup_pop () is implemented in a macro manner, which is a macro definition in Pthread.h:
#define Pthread_cleanup_push (Routine,arg) \
{
struct _pthread_cleanup_buffer _buffer; \
_pthread_cleanup_push (&_buffer, (routine), (ARG));
#define PTHREAD_CLEANUP_POP (execute) \
_pthread_cleanup_pop (&_buffer, (execute));
}
Visible, Pthread_cleanup_push () has a "{", and Pthread_cleanup_pop () has a "}", so the two functions must appear in pairs and must be in a code snippet at the same level of the program to compile.
Pthread_cleanup_pop parameter Execute if it is a value other than 0, log off a previously registered cleanup function in the order of the stack and execute the function; When the parameter of the Pthread_cleanup_pop () function is 0 o'clock, only the thread calls Pthread_ When the exit function or other thread calls the Pthread_cancel function on this thread, the cleanup function is executed while the cleanup function is ejected.
Example:
#include <stdio.h>
#include <pthread.h>
void Cleanfunc (void *parg)
{
printf ("Cleanfunc (%d) \ n", (int) parg);
}
void *threadfunc (void *parg)
{
Pthread_cleanup_push (Cleanfunc, (void *) 1);
Pthread_cleanup_push (Cleanfunc, (void *) 2);
Sleep (2);
Pthread_cleanup_pop (1);
Pthread_cleanup_pop (1);
}
int main ()
{
pthread_t Thdid;
Pthread_create (&thdid, NULL, ThreadFunc, (void *) 2);
Pthread_join (Thdid,null);
return 0;
}
The result of the operation is:
Cleanfunc (2)
Cleanfunc (1)
If the inside of the two times Pthread_cleanup_pop (1); Change to Pthread_cleanup_pop (0); guess what?
À does not have any output (at this point the Cleanfunc function is not executed)
If you change to 0 and then add pthread_exit (NULL) after sleep (2), the result is:
à with pthread_cleanup_pop (1); The result is the same.
Example: Use Pthread_cleanup_push and Pthread_cleanup_pop to release memory space allocated by child threads
#include <stdio.h>
#include <pthread.h>
#include <malloc.h>
void Freemem (void * args)
{
Free (args);
printf ("Clean up the memory!\n");
}
void* threadfunc (void *args)
{
Char *p = (char*) malloc (10); Allocate Memory for yourself
Pthread_cleanup_push (FREEMEM,P);
int i = 0;
for (; i <; i++)
{
printf ("Hello,my name is wangxiao!\n");
Sleep (1);
}
Pthread_exit ((void*) 3);
Pthread_cleanup_pop (0);
}
int main ()
{
pthread_t Pthid;
Pthread_create (&pthid, NULL, THREADFUNC, NULL);
int i = 1;
for (; i < 5; i++)//The parent thread runs less than a child thread, and when the parent thread ends, the child thread exits if no Pthread_join function waits for the child thread to execute, i.e. the child thread executes only 4 times.
{
printf ("Hello,nice to meet you!\n");
Sleep (1);
if (i% 3 = = 0)
Pthread_cancel (Pthid); Indicates that when the i%3==0 is canceled, the function causes a direct exit and does not execute the code of the Purple free section above, that is, the space failure is freed. To release the variable p of the pointer type, you must use the Pthread_cleanup_push and Pthread_cleanup_pop functions to free up space
}
int retvalue = 0;
Pthread_join (Pthid, (void**) &retvalue); Waits for the child thread to free up space and gets the return value of the child thread
printf ("Return value is:%d\n", RetValue);
return 0;
}
Linux Multithreading (ii) (thread wait, exit)