场景
1.多线程应用里, 线程基本上都是出自线程池, 那么基本不能使用pthread_cancel这类API, 因为它会终止线程运行, 线程终止后不能再次循环使用, 这对性能要求高的软件时基本是不会用pthread_cancel来停止逻辑运行的.
2.自行设计的可预测伪线程停止,其实就是停止执行当前的业务逻辑,并不是终止线程, 让线程回归线程池. 目前我发现的方案基本上离不开对状态变量的判断. (比较忙, 没有参考那些其他大公司的开源项目, 如有不足,请批评指正), 这里只说我发现的一种方案, 使用specific data,线程本地存储.
说明
1.pthread也可以类似Win32一样使用线程本地存储, 使用方式是差不多的, 参考线程本地存储. 关键的地方就是创建一个默认key来存储任务对象, 通过判断任务对象的值来中断逻辑执行. 大部分情况下是线程A 正在执行逻辑A, 线程B接收到客户终止任务执行请求, 通过获取到这个任务对象A, 并修改任务对象A的状态, 这时线程A 判断到任务对象A的状态时Abort时, 退出执行循环.
例子
// test-pthread-stop.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <stdint.h>
#include "pthread.h"
pthread_key_t gTaskKey;
typedef enum kTaskStatus1
{
kTaskStatusOk = 0,
kTaskStatusDoing,
kTaskStatusAbort,
kTaskStatusFinish
}kTaskStatus;
struct IPCPacket
{
uint64_t _id; //Packet id
uint8_t status; //Packet 状态
uint32_t command_type; //Packet 命令类型
void* data; //接收和发送数据.
uint32_t data_length; //数据长度.
};
static bool TestIsAbort(){
void* data = pthread_getspecific(gTaskKey);
// pthread specific data 默认是 NULL.
IPCPacket* packet = (IPCPacket*)data;
if(packet && packet->status == kTaskStatusAbort)
return true;
return false;
}
static void DoWork(void* data){
for(int i = 0; ; ++i){
Sleep(1000);
if(TestIsAbort()){
std::cout << "StartThread Abort: " << i << std::endl;
break;
}else{
std::cout << "StartThread: " << i << std::endl;
}
}
}
void* StartThread(void* data){
IPCPacket* task = (IPCPacket*)data;
pthread_setspecific(gTaskKey,task);
DoWork(data);
return NULL;
}
void TestThreadAbort(){
pthread_key_create(&gTaskKey,NULL);
IPCPacket task;
memset(&task,0,sizeof(task));
int count = 0;
pthread_t t1;
pthread_create(&t1,NULL,StartThread,&task);
Sleep(3000);
task.status = kTaskStatusAbort;
pthread_join(t1,NULL);
}
int _tmain(int argc, _TCHAR* argv[])
{
std::cout << "TestThreadAbort Begin" << std::endl;
TestThreadAbort();
std::cout << "TestThreadAbort End" << std::endl;
system("pause");
return 0;
}
输出:
TestThreadAbort Begin
StartThread: 0
StartThread: 1
StartThread Abort: 2
TestThreadAbort End