pthread_cleanup_push和pthread_cleanup_pop学习

pthread_cleanup_push:注册线程退出时的处理程序,与进程的atexit函数类似,只是以压栈的方式储存。

pthread_cleanup_pop:调用已经压栈的线程退出处理程序,当参数非零。

注册的线程退出处理函数仅在以下三种情况下才会被调用:

1、调用pthread_exit退出线程时;

2、响应取消请求时;

3、用非零参数调用pthread_cleanup_pop函数。

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

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");
	printf("thread 1 push complete\n");

	if(arg)
	{
		return (void *)1;
	}

	pthread_cleanup_pop(1);
	printf("here %d\n",__LINE__);

	pthread_cleanup_pop(2);
	return (void *)1;
}

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");
	printf("thread 2 push complete\n");

	if(arg)
	{
		pthread_exit((void *)2);
	}

	printf("thread 2 is %d\n",__LINE__);
	pthread_cleanup_pop(0);
	printf("thread 2 here is %d\n",__LINE__);
	pthread_cleanup_pop(0);

	return (void *)2;
}

int main()
{
	int err;
	pthread_t tid1,tid2;
	void *tret;

	err = pthread_create(&tid1,NULL,thr_fn1,(void *)1);
	if(0 != err)
	{
		printf("error:%s\n","cann't create thread 1");
	}

	err = pthread_create(&tid2,NULL,thr_fn2,(void *)2);
	if(0 != err)
	{
		printf("error:%s\n","cann't create thread 2");
	}
	
	err = pthread_join(tid1,&tret);
	if(0 != err)
	{
		printf("error:%s\n","cann't join with thread 1");
	}
	printf("thread 1 exit code %ld\n",(long)tret);

	err = pthread_join(tid2,&tret);
	if(0 != err)
	{
		printf("error:%s\n","cann't join with thread 2");
	}
	printf("thread 2 exit code %ld\n",(long)tret);

	exit(0);
}

注意点:

1、pthread_cleanup_push和pthread_cleanup_pop两个函数必须成对出现,压栈两个就必须弹栈两个,否则编译会报错,而且报的很莫名其妙;

2、调用顺序与压栈的时候恰好相反,如果压栈时fun1 --> fun2;调用的顺序就是fun2 --> fun1。

至于pthread_cleanup_pop的参数貌似只有零和非零的区分。因为此时会调用压栈的函数,而函数的参数是当初压栈的时候就已经确定了,与pthread_cleanup_pop的参数毫无关系。



你可能感兴趣的:(线程,apue,Unix环境高级编程)