Bootstrap

09LinuxC线程学习之pthread_cancel函数及其案例

1 pthread_cancel函数

int pthread_cancel(pthread_t thread);	
/*
	功能:杀死(取消)线程,其作用,对应进程中kill()函数。
	成功:0;失败:错误号。
	参1:要杀死线程的tid。
*/

2 pthread_cancel函数案例

2.1 案例1

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

void *tfn(void *arg){
	
	while(1){
		printf("thread pid=%d, tid=%lu\n", getpid(), pthread_self());
		sleep(1);
	)

	return NULL;
}

int main(int argc, char *argv[]){
	
	pthread_t tid;
	tid[i] = -1;

	int ret = pthread_create(&tid[i], NULL, tfn, NULL);
	if(ret != 0){
		fprintf(stderr, "pthread_create failed:%s\n", strerror(ret));
		exit(1);
	}

	printf("main pid=%d, tid=%lu\n", getpid(), pthread_self());
	
	sleep(5);
	
	pthread_cancel(tid);//终止线程,但需要一个执行的CPU分片
	if(ret != 0){
		fprintf(stderr, "pthread_create failed:%s\n", strerror(ret));
		exit(1);
	}
	
	while(1);

	return 0;
}

上面代码结果,当我们每一秒在子线程打印,5秒后主线程调用cancel函数成功杀死子线程。
在这里插入图片描述

2.2 案例2

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


void *tfn1(void *arg)
{
	printf("thread 1 returning\n");

	return (void *)111; 
}

void *tfn2(void *arg)
{
	printf("thread 2 exiting\n");
	pthread_exit((void *)222);
}

void *tfn3(void *arg)
{
	while (1) {
		//printf("thread 3: I'm going to die in 3 seconds ...\n");
		//sleep(1);
		//pthread_testcancel();	//自己添加取消点*/
	}

    return (void *)666;
}

int main(void)
{
	pthread_t tid;
	void *tret = NULL;

	pthread_create(&tid, NULL, tfn1, NULL);
	pthread_join(tid, &tret);
	printf("thread 1 exit code = %d\n\n", (int)tret);

	pthread_create(&tid, NULL, tfn2, NULL);
	pthread_join(tid, &tret);
	printf("thread 2 exit code = %d\n\n", (int)tret);

	pthread_create(&tid, NULL, tfn3, NULL);
	sleep(3);
    pthread_cancel(tid);
	pthread_join(tid, &tret);
	printf("thread 3 exit code = %d\n", (int)tret);

	return 0;
}


结果分析,上面代码是第三个线程在主线程结束后将被杀死,但是图中并未杀死打印出:thread 3 exit codexxx,而是子线程继续卡死执行while(1)循环。这是为什么呢?这是因为调用pthread_cancel杀死子线程必须有系统调用函数,例如添加sleep()或者其它,注意if,switch这些不是系统调用,所以也不会给契机pthread_cancel杀死子线程。最好的方法是调用pthread_testcancel,它内部作了系统调用的处理。
在这里插入图片描述

3 总结pthread_cancel

  • 1)pthread_cancel可以杀死子线程,但必须需要一个契机,这个契机就是系统调用。一般方法是调用pthread_testcancel提供契机处理。并且join再回收该被杀死的子线程的返回值为pthread.h中的宏#define PTHREAD_CANCELED ((void *) -1)。
;