[并发并行]_[线程取消]_[Pthread的线程取消特性]

场景

1.大多数情况下我们都从线程池获取工作线程执行任务,线程池的线程缺点就是不能使用线程的取消特性. 因为线程取消(停止)就是终止线程, 终止后的线程不能再次重用.

2.在有线程池的情况下, pthread_cancel 目前发现只能用在程序退出时终止所有线程. 至于线程池的取消操作, 有很多种方法, 比如使用Thread-specific data.(最终还是要判断某个变量)

3.如果没有线程池, 那么可以用pthread_cancel来终止线程.

4.一般线程取消用在快速响应界面请求或者释放资源的情形.

说明

1.pthread线程取消类型有两种, Deferred(延迟)和 Asynchronous(异步). Defrerred:在下一个取消点函数调用时终止线程,取消点函数包括


pthread_testcancel
pthread_cond_wait
pthread_cond_timewait
pthread_join
...

在Linux上, 只要有关信号响应的函数都可作为取消点; Windows上还是老老实实用pthread相关函数吧. 有一点要注意, pthread_mutex_lock并不是取消检查点. 它是安全的取消类型, 因为取消点是可以预估的.

Asynchronous: 异步取消, 它可以在任何时候终止线程. 所以它适合在非锁环境和非复杂创建销毁内存的环境, 当然退出程序除外. 它不是安全的取消类型, 如果要使用, 需要编码确保上下文安全.

2.以下有个例子, 比较全面的说明了取消的相关函数, 该例子使用pthread-win32和vs2010.

int pthread_cancel(pthread_t thread);
int pthread_setcancelstate (int state,int *oldstate);
int pthread_setcanceltype (int type,int *oldtype);
int pthread_testcancel (void);
void pthread_cleanup_push(void (*routine)(void *),void *arg);
void pthread_cleanup_pop(int execute);

例子


// test-pthread.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <Windows.h>
#include <iostream>
#include <memory>
#include "pthread.h"

class A
{
public:
	~A(){
		std::cout << "~A: " << i << std::endl;
	}
	int i;
};


#define SIZE    10      /* array size */

static int matrixa[SIZE][SIZE];
static int matrixb[SIZE][SIZE];
static int matrixc[SIZE][SIZE];

// 摘录部分 cancel_async.c
static void BusyWorkUnControl(int& index){
    int i, j, k, value = 1;
    
    /*
     * Initialize the matrices to something arbitrary.
     */
    for (i = 0; i < SIZE; i++)
        for (j = 0; j < SIZE; j++) {
            matrixa[i][j] = i;
            matrixb[i][j] = j;
        }

    while (1) {
		++index;
        /*
         * Compute the matrix product of matrixa and matrixb.
         */
        for (i = 0; i < SIZE; i++)
            for (j = 0; j < SIZE; j++) {
                matrixc[i][j] = 0;
                for (k = 0; k < SIZE; k++)
                    matrixc[i][j] += matrixa[i][k] * matrixb[k][j];
            }

        /*
         * Copy the result (matrixc) into matrixa to start again
         */
        for (i = 0; i < SIZE; i++)
            for (j = 0; j < SIZE; j++)
                matrixa[i][j] = matrixc[i][j];
    }
}

static void* AsyncCancelThread(void* data){
	int type = 0;
	// 设置异步取消
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&type);

	// 密集计算性, 比如调用第3方接口或者进行音视频转换.
	// 在退出程序时尤其有效,应用在密集运行区间.
	// 注意线程不要有mutex加锁操作,因为系统可能会产生不可查询的中断.
	int* count = (int*)data;
	BusyWorkUnControl(*count);
	pthread_setcanceltype(type,&type);
	return NULL;
}

static void CleanUp(void* data){
	std::cout << "CleanUp" << std::endl;
	free(data);
}

static void* DeferredThread(void* data){

	char* buf = (char*)malloc(16);
	int* count = (int*)data;

	// 如果调用了取消操作,清理函数就会在函数结束前调用.
	pthread_cleanup_push(CleanUp,buf);

	A* a = new A();
	std::shared_ptr<A> sp_a(a); // 使用shared_ptr来释放资源.

	int state = 0, status = 0;
	for(; (*count)< 1000; ++(*count)){
		Sleep(100);
		a->i = *count;

		if(a->i % 90 == 0){
			// 延迟取消,如果判断任务快完成,可以重置取消状态.
			// 这里我们判断完成到达90时,只要到达100,即可完成第一阶段,所以设置Disable状态,让达到 100.
			// 因为如果不设置状态,如果遇到取消点,一样会返回.
			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&state);
		}else if(a->i % 100 == 0){
			// 还原状态.
			pthread_setcancelstate(state,&state);
			pthread_testcancel();
		}else{
			//pthread_testcancel();
		}
	}

	// 非零: 表示需要调用清理函数.
	pthread_cleanup_pop(1);

	// 取消后以下基本不会执行
	std::cout << "DeferredThread: " << *count << std::endl;
	*count = 0;
	return NULL;
}

void TestDeferredCancel(){
	int count = 1;
	pthread_t t1;
	pthread_create(&t1,NULL,DeferredThread,&count);

	Sleep(2000);
	// 默认情况下,取消状态是延期的deferred
	pthread_cancel(t1);

	void* result = NULL;
	pthread_join(t1,&result);
	
	if(result == PTHREAD_CANCELED){
		std::cout << "Thread Cancel: " << count << std::endl;
	}else{
		std::cout << "Thread Not Cancel: " << count << std::endl;
	}
}

void TestAsyncCancel(){
	int count = 1;
	pthread_t t1;
	pthread_create(&t1,NULL,AsyncCancelThread,&count);

	Sleep(2000);
	// 默认情况下,取消状态是延期的deferred
	pthread_cancel(t1);

	void* result = NULL;
	pthread_join(t1,&result);
	
	if(result == PTHREAD_CANCELED){
		std::cout << "Thread Cancel: " << count << std::endl;
	}else{
		std::cout << "Thread Not Cancel: " << count << std::endl;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	std::cout << "TestDeferredCancel Begin" << std::endl;
	TestDeferredCancel();
	std::cout << "TestDeferredCancel End" << std::endl;

	std::cout << "TestAsyncCancel Begin" << std::endl;
	TestAsyncCancel();
	std::cout << "TestAsyncCancel End" << std::endl;

	system("pause");
	return 0;
}



输出:

TestDeferredCancel Begin
CleanUp
Thread Cancel: 100
TestDeferredCancel End
TestAsyncCancel Begin
Thread Cancel: 485616
TestAsyncCancel End

参考

pthread_cancel
pthread_cleanup_push
Programming With POSIX Threads
pthreads-cancel-blocking-thread
pthreads-win32

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter(阿斯拉达)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值