线程的取消

#include <pthread.h>

/*
 *功能:
 *  取消线程
 *参数:
 *  thread:目标线程 ID
 *return:
 *  成功:0
 *  失败:出错编号
 */
int pthread_cancel(pthread_t thread);

     pthread_cancel 函数的实质是发信号给目标线程 thread, 使目标线程退出

     此函数只是发送终止信号给目标线程, 不会等待取消目标线程执行完才返回

    然而发送成功并不意味着目标线程一定就会终止, 线程被取消时, 线程的取消属性会决定线程能否被取消以及何时被取消

线程的取消状态

       即线程能不能被取消
线程取消点

      即线程被取消的地方
线程的取消类型

       在线程能被取消的状态下, 是立马被取消结束还是执行到取消点的时候被取消结束

 

线程的取消状态

/*
 *功能:
 *  在 Linux 系统下, 线程默认可以被取消
 *  编程时可以通过 pthread_setcancelstate 函数设置线程是否可以被取消
 *参数:
 *  state:
 *    PTHREAD_CANCEL_DISABLE: 不可以被取消
 *    PTHREAD_CANCEL_ENABLE: 可以被取消
 *  old_state:
 *    保存调用线程原来的可取消状态的内存地址
 */
pthread_setcancelstate(int state, int *old_state);

验证设置线程能 否被取消, 然后看线程能不能被取消

 

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

void *thread_cancel(void *arg);

int main(int argc, char *argv[])
{
	pthread_t tid1;
	int ret = 0;
	pthread_create(&tid1, NULL, thread_cancel, NULL);
	if(ret != 0)
	{
		perror("pthread_create");
	}
	sleep(3);
	pthread_cancel(tid1);
	pthread_join(tid1, NULL);
	return 0;
}

void *thread_cancel(void *arg)
{
	//pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	while(1)
	{
		printf("this is my new thread_cancel\n");
		sleep(1);
	}
	return NULL;
}

线程的取消点

/*
 *功能:
 *  线程被取消后,该线程并不是马上终止,默认情况下线程执行到消点时才能被终止
 *  编程时可以通过pthread_testcancel 函数设置线程的取消点
 *  当别的线程取消调用此函数的线程时候,被取消的线程执行到此函数时结束
 */
void pthread_testcancel(void);
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void *thread_cancel(void *arg);

int main(int argc, char *argv[]);
{
	pthread_t tid1;
	int ret = 0;
	pthread_create(&tid1, NULL, thread_cancel, NULL);
	if(ret != 0)
	{
		perror("pthread_create");
	}
	sleep(3);
	pthread_cancel(tid1);
	pthread_join(tid1, NULL);
	return 0;
}

void *thread_cancel(void *arg)
{
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	while(1)
	{
		pthread_testcancel();
	}
	
	return NULL;
}

 线程的取消类型

/*
 *功能:
 *  线程被取消后,该线程并不是马上终止,默认情况下线程执行到消点时才能被终止
 *  编程时可以通过pthread_setcanceltype 函数设置线程是否可以立即被取消
 *参数:
 *  type:
 *    PTHREAD_CANCEL_ASYNCHRONOUS: 立即取消
 *    PTHREAD_CANCEL_DEFERRED: 不立即被取消
 *  oldtype: 保存调用线程原来的可取消类型的内存地址
 */
pthread_setcanceltype(int type, int *oldtype);

 

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

void *thread_cancel(void *arg);

int main(int argc, char *argv[])
{
    pthread_t tid1;
    int ret = 0;
    pthread_create(&tid, NULL, thread_cancel, NULL);
    if(ret != 0)
    {
        perror("pthread_create");
    }
    sleep(3);
    pthread_cancel(tid1);
    pthread_join(tid1, NULL);
    return 0;
}

void *thread_cancel(void *arg)
{
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    while(1);
    return0;
}

线程退出清理函数

      和进程的退出清理一样, 线程也可以注册它退出时要调用的函数, 这样的函数称为线程清理处理程序(threadcleanup handler)

     注意:
          线程可以建立多个清理处理程序
          处理程序在栈中, 故它们的执行顺序与它们注册时的顺序相反

  注册清理函数

#include <pthread.h>

/*
 *功能:
 *  将清除函数压栈。 即注册清理函数
 *参数:
 *  routine: 线程清理函数的指针
 *  arg: 传给线程清理函数的参数
 */
void pthread_cleanup_push(void(*routine)(void *),void *arg);

  弹出清理函数

#include <pthread.h>

/*
 *功能:
 *  将清除函数弹栈, 即删除清理函数
 *参数:
 *  execute: 线程清理函数执行标志位
 *    非 0,弹出清理函数,执行清理函数
 *    0,弹出清理函数,不执行清理函数
 */
void pthread_cleanup_pop(int execute);

当线程执行以下动作时会调用清理函数: 

        调用 pthread_exit 退出线程

        响应其它线程的取消请求

        用非零 execute 调用 pthread_cleanup_pop

       无论哪种情况 pthread_cleanup_pop 都将删除上一次 pthread_cleanup_push 调用注册的清理处理函数

   验证线程调用 pthread_exit 函数时, 系统自动调用线程清理函数

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

void cleanup(void *arg);
void *thread(void *arg);

int main(int argc, char *argv[])
{
    pthread_t tid;
    //创建线程
    pthread_create(&tid, NULL, thread, NULL);
    pthread_join(tid, NULL);
    printf("process is dying\n");

    return 0;
}

void cleanup(void *arg)
{
    printf("clean up ptr = %s\n",(char *)arg);
    free((char *)arg);
}

void *thread(void *arg)
{
    char *ptr = NULL;

    //创建线程清理
    printf("this is new thread\n");
    ptr = (char *)malloc(100);

    pthread_cleanup_push(cleanup, (void *)(ptr));
    bzero(ptr, 100);
    strcpy(ptr, "memory from malloc");

    printf("before exit\n");
    pthread_exit(NULL);
    sleep(3);

    //push 与 pop配对使用 
    printf("before pop\n");
    pthread_cleanup_pop(1);
    return NULL;
}

 验证线程被取消时, 系统自动调用线程清理函数

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

void cleanup(void *arg);
void *thread(void *arg);

int main(int argc, char *argv[])
{
    pthread_t tid;
    pthread_create(&tid, NULL, thread, NULL);
    sleep(1);
    printf("before cancel\n");
    //子线程响应 pthread_cancel 后, 会执行线程处理函数
    pthread_cancel(tid);
    pthread_join(tid, NULL);
    printf("process is dying\n");
    return 0;
}

void cleanup(void *arg)
{
    printf("clean up ptr = %s\n",(char *)arg);
    free((char *)arg);
}

void *thread(void *arg)
{
    char *ptr = NULL;
    
    printf("this is new thread\n");
    ptr = (char *)malloc(100);
    pthread_cleanup_push(cleanup, (void *)(ptr));
    bzero(ptr, 100);
    strcpy(ptr, "memory form malloc");
    sleep(3);

    printf("before pop\n");
    pthread_cleanup_pop(1);
    return NULL;
}

验证调用 pthread_cleanup_pop 函数时, 系统自动调用线程清理函数

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

void cleanup_func1(void *arg);
void cleanup_func2(void *arg);
void *thread(void *arg);

int main()
{
    pthread_t tid;
    pthread_create(&tid, NULL, thread, NULL);
    pthread_join(tid, NULL);

    printf("process is dying\n");
    return 0;
}
void cleanup_func1(void *arg)
{
    printf("in cleanup funcl\n");
    printf("clean up ptr = %s\n",(char *)arg);
    free((char *)arg);
}

void cleanup_func2(void *arg)
{
    printf("in cleanup func2\n");
}

void *thread(void *arg)
{
    char *ptr = NULL;
    
    //创建线程清理
    printf("this is new thread\n");
    ptr = (char *)malloc(100);
    pthread_cleanup_push(cleanup_func1, (void *)(ptr));
    pthread_cleanup_push(cleanup_func2, NULL);
    bzero(ptr, 100);
    strcpy(ptr, "memory from malloc");
    
    printf("before pop\n");
    pthread_cleanup_pop(1);

    printf("before pop\n");
    pthread_cleanup_pop(1);
    return NULL;
}