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)spa

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

調用線程將一直阻塞,直到指定的線程調用pthread_exit、從啓動例程中返回或者被取消。
指針

此函數能夠得到線程的退出狀態。code

此函數是一種屏障,容許一個線程等待,直到另外一個線程退出。orm

(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自動把線程置於分離狀態。若是線程已經被分離,線程的底層存儲資源能夠在線程終止時當即被回收

相關文章
相關標籤/搜索