【原创】《Linux高级程序设计》杨宗德著 - Linux多线程编程 - 线程退出与等待


【原创】《Linux高级程序设计》杨宗德著 - Linux多线程编程 - 线程退出与等待


线程退出

新创建的线程从执行用户定义的函数处开始执行,直到出现以下情况时退出:

  • 调用pthread_exit函数退出。
  • 调用pthread_cancel函数取消该线程。
  • 创建线程的进程退出或者整个函数结束。
  • 其中的一个线程执行了exec类函数执行新的进程。


等待线程


退出线程示例

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void *helloworld(char *argc);
int main(int argc,int argv[])
{
	int error;
	int *temptr;	

	pthread_t thread_id;	

	pthread_create(&thread_id,NULL,(void *)*helloworld,"helloworld");
	printf("*p=%x,p=%x\n",*helloworld,helloworld);
	if(error=pthread_join(thread_id,(void **)&temptr))
	{
		perror("pthread_join");
		exit(EXIT_FAILURE);	
	}
	printf("temp=%x,*temp=%c\n",temptr,*temptr);
	*temptr='d';
	printf("%c\n",*temptr);
	free(temptr);
	return 0;
}

void *helloworld(char *argc)
{
	int *p;
	p=(int *)malloc(10*sizeof(int));
	printf("the message is %s\n",argc);
	printf("the child id is %u\n",pthread_self());
	memset(p,'c',10);
	printf("p=%x\n",p);
	pthread_exit(p);
	//return 0;
}
运行结果:

$ ./pthread_exit_test 
*p=80486b9,p=80486b9
the message is helloworld
the child id is 3076361024
p=b6c00468
temp=b6c00468,*temp=c
d

线程退出前操作

示例代码:

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

void cleanup()
{
	printf("cleanup\n");
}
void *test_cancel(void)
{
	pthread_cleanup_push(cleanup,NULL);
	printf("test_cancel\n");
	while(1)
	{
		printf("test message\n");
		sleep(1);
	}
	pthread_cleanup_pop(1);
}
int main()
{
	pthread_t tid;
	pthread_create(&tid,NULL,(void *)test_cancel,NULL);
	sleep(2);
	pthread_cancel(tid);
	pthread_join(tid,NULL);
}
运行结果:

$ ./pthread_pop_push 
test_cancel
test message
test message
test message
cleanup

取消线程


取消线程是指取消一个正在执行线程的操作,当然,一个线程能够被取消并终止执行需要满足以下条件:
该线程是否可以被其它取消,这是可以设置的,在Linux系统下,默认是可以被取消的,可用宏分配是PTHREAD_CANCEL_DISABLE和PTHREAD_CANCEL_ENABLE;
该线程处于可取消点才能取消。也就是说,该线程被设置为可以取消状态,另一个线程发起取消操作,该线程并不是一定马上终止,只能在可取消点才中止执行。可以设置为立即取消和在取消点取消。可用宏为PTHREAD_CANCEL_DEFERRED和PTHREAD_CANCEL_ASYNCHRONOUS。

设置可取消状态 


可设置的state的合法值:

  • 如果目标线程的可取消性状态为PTHREAD_CANCEL_DISABLE,则针对目标线程的取消请求将处于未决状态,启用取消后才执行取消请求。
  • 如果目标线程的可取消性状态为PTHREAD_CANCEL_ENABLE,则针对目标线程的取消请求将被传递。默认情况下,在创建某个线程时,其可取消性状态设置为PTHREAD_CANCEL_ENABLE。

设置取消类型

pthread_setcanceltype()函数用来设置取消类型,即允许取消的线程在接收到取消操作后是立即中止还是在取消点中止,该函数声明如下:

extern int pthread_setcanceltype (int __type, int *__oldtype)
此函数有两个参数,type为调用线程的可取消性类型所要设置的值。oldtype为存储调用线程原来的可取消性类型的地址。type的合法值包括:
如果目标线程的可取消性状态为PTHREAD_CANCEL_ASYNCHRONOUS,则可随时执行新的或未决的取消请求。
如果目标线程的可取消性状态为PTHREAD_CANCEL_DEFERRED,则在目标线程到达一个取消点之前,取消请求将一直处于未决状态。
在创建某个线程时,其可取消性类型设置为PTHREAD_CANCEL_DEFERRED。

示例代码

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

void *thread_function(void *arg);

int main(int argc,char *argv[]) 
{
    int res;
    pthread_t a_thread;
    void *thread_result;

    res = pthread_create(&a_thread, NULL, thread_function, NULL);
    if (res != 0) 
   {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }

    printf("Cancelling thread...\n");
    sleep(10);	
    res = pthread_cancel(a_thread);
    if (res != 0) 
   {
        perror("Thread cancelation failed");
        exit(EXIT_FAILURE);
    }

    printf("Waiting for thread to finish...\n");
    sleep(10);	
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) 
    {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) 
{
    int i, res, j;
    sleep(1);
    res = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    if (res != 0) 
    {
        perror("Thread pthread_setcancelstate failed");
        exit(EXIT_FAILURE);
    }
    printf("thread cancle type is disable,can't cancle this thread\n");
    for(i = 0; i <3; i++) 
    {
        printf("Thread is running (%d)...\n", i);
        sleep(1);
    }

    res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    if (res != 0) 
    {
        perror("Thread pthread_setcancelstate failed");
        exit(EXIT_FAILURE);
    }
    else
	printf("Now change ths canclestate is ENABLE\n");
   sleep(200); 
   pthread_exit(0);
}
运行结果:

$ ./pthread_cancle_example 
Cancelling thread...
thread cancle type is disable,can't cancle this thread
Thread is running (0)...
Thread is running (1)...
Thread is running (2)...
Now change ths canclestate is ENABLE
Waiting for thread to finish...

线程与私有数据

在多线程程序中,经常要用全局变量来实现多个函数间的数据共享。由于数据空间是共享的,因此全局变量也为所有进程共有。但有时应用程序设计中必要提供线程私有的全局变量,这个变量仅在线程中有效,但却可以跨过多个函数访问。
比如在程序里可能需要每个线程维护一个链表,而会使用相同的函数来操作这个链表,最简单的方法就是使用同名而不同变量地址的线程相关数据结构。这样的数据结构可以由 Posix 线程库维护,成为线程私有数据 (Thread-specific Data,或称为 TSD)。
这里主要测试和线程私有数据有关的 4 个函数:

pthread_key_create();
pthread_key_delete();

pthread_getspecific();
pthread_setspecific();

示例代码(使用全局同名变量的情况):

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

int key=100;
void *helloworld_one(char *argc)
{
	printf("the message is %s\n",argc);
	key=10;
	printf("key=%d,the child id is %u\n",key,pthread_self());
	return 0;
}

void *helloworld_two(char *argc)
{
	printf("the message is %s\n",argc);
	sleep(1);
	printf("key=%d,the child id is %u\n",key,pthread_self());
	return 0;
}
int main()
{

	pthread_t thread_id_one;
	pthread_t thread_id_two;

	pthread_create(&thread_id_one,NULL,(void *)*helloworld_one,"helloworld");
	pthread_create(&thread_id_two,NULL,(void *)*helloworld_two,"helloworld");
	pthread_join(thread_id_one,NULL);
	pthread_join(thread_id_two,NULL);
}
运行结果:

$ ./pthread_glob_test 
the message is helloworld
the message is helloworld
key=10,the child id is 3075849024
key=10,the child id is 3067456320

示例代码(使用线程私有数据的情况):

//this is the test code for pthread_key 

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

pthread_key_t key; 
void echomsg(void *t) 
{ 
	printf("destructor excuted in thread %u,param=%u\n",pthread_self(),((int *)t)); 
} 

void * child1(void *arg) 
{ 
	int i=10;
	int tid=pthread_self(); 
	printf("\nset key value %d in thread %u\n",i,tid); 
	pthread_setspecific(key,&i); 
	printf("thread one sleep 2 until thread two finish\n");
	sleep(2); 
	printf("\nthread %u returns %d,add is %u\n",tid,*((int *)pthread_getspecific(key)),(int *)pthread_getspecific(key)); 
} 

void * child2(void *arg) 
{ 
	int temp=20;
	int tid=pthread_self(); 
	printf("\nset key value %d in thread %u\n",temp,tid); 
	pthread_setspecific(key,&temp); 
	sleep(1); 
	printf("thread %u returns %d,add is %u\n",tid,*((int *)pthread_getspecific(key)),(int *)pthread_getspecific(key)); 
} 

int main(void) 
{ 
	pthread_t tid1,tid2; 
	pthread_key_create(&key,echomsg); 
	pthread_create(&tid1,NULL,(void *)child1,NULL); 
	pthread_create(&tid2,NULL,(void *)child2,NULL); 
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	pthread_key_delete(key); 
	return 0; 
} 
运行结果:

$ ./pthread_key_test 

set key value 20 in thread 3067337536

set key value 10 in thread 3075730240
thread one sleep 2 until thread two finish
thread 3067337536 returns 20,add is 3067335512
destructor excuted in thread 3067337536,param=3067335512

thread 3075730240 returns 10,add is 3075728216
destructor excuted in thread 3075730240,param=3075728216

原文链接:

http://blog.csdn.net/geng823/article/details/41285251

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值