示例 demo
最简单的 demo:
static void* thread1_func(void *arg)
{int i = 0;// able to be cancelpthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);for(i=0; ; i++) {printf("thread1 %d\n", i);sleep(1);}
}int main(int argc, char **argv)
{pthread_t t;void *res;pthread_create(&t, NULL, thread1_func, NULL);sleep(3);pthread_cancel(t);          // cancel thread1pthread_join(t, &res);      // wait thread1if (res == PTHREAD_CANCELED)printf("thread1 was terminate by cancel\n");elseprintf("thread1 was not terminate by cancel\n");exit(EXIT_SUCCESS);
}
为了突出重点,省略了检查返回值。
运行效果:
thread1 0
thread1 1
thread1 2
thread1 was terminate by cancel
主线程先创建线程 thread1,然后睡眠 3 秒后发出终止 thread1 的请求。
接收到终止请求后,thread1 会在合适的时机被终止掉。
主线程通过 pthread_join() 阻塞等待 thread1 退出。
几个要点
线程终止的 4 种方式:
- 线程的执行函数返回了,这和 main() 函数结束类似。 
- 线程调用了 pthread_exit() 函数,这和调用 exit() 返回类似。 
- 线程被另一个线程通过 pthread_cancel() 函数取消,这和通过kill() 发送 SIGKILL 信号类似。 
- 进程终止了,则进程中的所有线程也会终止。 
取消某个线程的常规步骤
被取消的线程:
- 允许取消,pthread_setcancelstate(),参数可选值: 
- PTHREAD_CANCEL_ENABLE,这是默认值; 
- PTHREAD_CANCEL_DISABLE; 
- 设置取消类型,pthread_setcanceltype(),参数可选值: 
- PTHREAD_CANCEL_ASYNCHRONOUS,异步方式,当发出取消请求后,线程可能会在任何点被杀死。 
- PTHREAD_CANCEL_DEFERRED,延迟方式,线程只会在特定的取消点(cancellation points,调用某个函数前)被杀死。 
 - 发起取消的线程: - 发送取消要求,pthread_cancel(),发出取消请求后,pthread_cancel() 当即返回,不会等待目标线程的退出。 
- 等待取消完成,pthread_join()。 
 - 哪些函数是取消点? - POSIX.1 指定了哪些函数一定是取消点: - 点击查看大图 - 更多关于取消点的介绍: - $ man 7 pthreadsCancellation points...accept()aio_suspend()clock_nanosleep()close()...- 阅读开源软件 MJPG-streamer- MJPG-streamer 是什么? - 简单地说,就是一个开源的流媒体服务器: - https://github.com/jacksonliam/mjpg-streamer - 通过 mjpg-streamer,你可以通过 PC 浏览器访问到板子上的摄像头图像。 - MJPG-streamer 是如何结束工作线程的? - MJPG-streamer 运行时一般会有 3 个线程: - 主线程; 
- 负责数据的输入的线程 (例如 camera capture thread); 
- 负责输出数据的线程 (例如 http server thread). 
 - 以 http server thread 为例: - plugins/output_http/httpd.cvoid *server_thread(void *arg) {...pthread_cleanup_push(server_cleanup, pcontext);// 处理连接while(!pglobal->stop) {...}pthread_cleanup_pop(1); }- pthread_cleanup_push() 用于注册清理函数到栈中,当线程遭取消时,会沿该栈自顶向下依次执行清理函数。 - 当用户通过按下 ctrl + c 要求结束程序时,主线程会要求杀掉 http server thread 等各种线程: - static void signal_handler(int sig) {for(i = 0; i < global.outcnt; i++) {...pthread_cancel(servers[id].threadID);...} }- 接下来,当 http server thread 遇到某个取消点时,server_cleanup() 会被调用以完成清理工作。 - 这里只是简单地分析一下,MJPG-Streamer 里多线程相关的代码挺复杂的,有兴趣的小伙伴们自行阅读吧。 - 相关参考- 开源软件 / MJPG-Streamer 
- Linux 系统编程(第2版) / 7.7.6 终止线程 
- Linux 程序设计(第4版) / 12.7 取消一个线程 
- Linux-Unix 系统编程手册 / 32 线程:线程取消 
- Unix 环境高级编程 / 11.5 线程终止 
 - 思考技术,也思考人生- 要学习技术,更要学习如何生活。 - 你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。 - 推荐阅读: - 专辑|Linux文章汇总 - 专辑|程序人生 - 专辑|C语言 - 我的知识小密圈