APUE学习笔记-11.5线程终止

<312>获得线程退出状态

#include "myapue.h"
#include <pthread.h>

void *thr_fn1(void *arg)
{
	printf("thread 1 returning\n");
	return((void *)1); 
}

void *thr_fn2(void *arg)
{
	printf("thread 2 returning\n");
	pthread_exit((void *)2); 
}

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

	err = pthread_create(&tid1, NULL, thr_fn1, NULL);
	if(err != 0)
		err_exit(err, "can't create thread 1");
	err = pthread_create(&tid2, NULL, thr_fn2, NULL);
	if(err != 0)
		err_exit(err, "can't create thread 2");
		
	err = pthread_join(tid1, &tret);
	if(err != 0)
		err_exit(err, "can't join with thread 1");
	printf("thread 1 exit code %ld\n", (long)tret);
	
	err = pthread_join(tid2, &tret);
	if(err != 0)
		err_exit(err, "can't join with thread 2");
	printf("thread 2 exit code %ld\n", (long)tret);
	
	exit(0);	
}

(1)

 int pthread_join(pthread_t thread, void **retval);

调用线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。

此函数可以获得线程的退出状态。

此函数是一种屏障,允许一个线程等待,直到另一个线程退出。

(2)

void pthread_exit(void *retval);

(3)

单个线程可以通过3种方式退出:

1)简单地从启动例程中返回,返回值是线程的退出码。

2)线程可以被同一进程中的其他线程取消。

3)线程调用pthread_exit。

(4)

进程中的任意线程调用了exit相关函数,整个进程就会终止。

<314>

(1)

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

                          void *(*start_routine) (void *), void *arg);

void pthread_exit(void *retval);

这两个函数的无类型指针参数可以传递包含复杂信息的结构的地址。但由于传递的是地址,则要注意,这个结构所使用的内存在调用者完成调用以后必须任然有效。

#include "apue.h"
#include <pthread.h>

struct foo {
	int a, b, c, d;
};

void
printfoo(const char *s, const struct foo *fp)
{
	printf("%s", s);
	printf("  structure at 0x%lx\n", (unsigned long)fp);
	printf("  foo.a = %d\n", fp->a);
	printf("  foo.b = %d\n", fp->b);
	printf("  foo.c = %d\n", fp->c);
	printf("  foo.d = %d\n", fp->d);
}

void *
thr_fn1(void *arg)
{
	struct foo	foo = {1, 2, 3, 4};

	printfoo("thread 1:\n", &foo);
	pthread_exit((void *)&foo);
}

void *
thr_fn2(void *arg)
{
	printf("thread 2: ID is %lu\n", (unsigned long)pthread_self());
	pthread_exit((void *)0);
}

int
main(void)
{
	int			err;
	pthread_t	tid1, tid2;
	struct foo	*fp;

	err = pthread_create(&tid1, NULL, thr_fn1, NULL);
	if (err != 0)
		err_exit(err, "can't create thread 1");
	err = pthread_join(tid1, (void *)&fp);
	if (err != 0)
		err_exit(err, "can't join with thread 1");
	sleep(1);
	printf("parent starting second thread\n");
	err = pthread_create(&tid2, NULL, thr_fn2, NULL);
	if (err != 0)
		err_exit(err, "can't create thread 2");
	sleep(1);
	printfoo("parent:\n", fp);
	exit(0);
}

(2)

此程序中,主线程定义了结构变量fp,结构的内容在线程tid1的栈上分配,但线程tid1退出后这个结构的地址就失效了,所以主线程中在此使用这个变量时,打印的是无效的内容。其内容已被第二个线程tid2的栈覆盖。

<317>

#include "apue.h"
#include <pthread.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(0);
	pthread_cleanup_pop(0);
	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);
	pthread_cleanup_pop(0);
	pthread_cleanup_pop(0);
	pthread_exit((void *)2);
}

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

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

(1)

void pthread_cleanup_push(void (*routine)(void *),  void *arg);

此函数用于安排线程清理处理程序。

void pthread_cleanup_pop(int execute);

这两个函数必须在与线程相同的作用域中以匹配对的形式使用。

(2)

当线程执行以下动作时执行清理函数。

    调用pthread_exit时

    响应取消请求时。(int pthread_cancel(pthread_t thread);

    用非零execute参数调用pthread_cleanup_pop时。(如果execute设置为0,清理函数将不被调用)

如果线程是通过从它的启动例程中返回而终止的话,它的清理处理程序就不会被调用。

(3)

线程的终止状态会保存直到对该线程调用pthread_join。(pthread_join自动把线程置于分离状态。如果线程已经被分离,线程的底层存储资源可以在线程终止时立即被回收


你可能感兴趣的:(APUE学习笔记-11.5线程终止)