【PTHREAD】线程退出与取消
1 线程退出
线程正常退出的几种方式:
-
在线程工作函数中调用
pthread_exit
,此时可使用pthread_join
接收pthread_exit
的参数值 -
线程工作函数运行结束
-
同一进程中的任意一个子线程调用
exit
,或者主线程结束 -
线程可以被从另一个线程中取消
pthread_cancel
1.1 API
void pthread_exit(void *retval);
- 如果为链接态线程,参数
retval
指示的返回值,可用pthread_join
进行接收
1.2 案例:显式退出链接态线程
-
源码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> void *start_routine(void *ptr) { printf("子线程(%lu)开始运行...\n", pthread_self()); int num = 0; while (1) { printf("子线程(%lu)正在执行,%d...\n", pthread_self(), ++num); sleep(1); if (num > 3) pthread_exit((void **)"8888"); } printf("子线程(%lu)即将退出...\n", pthread_self()); return (void *)"9999"; } int main(int argc, char const *argv[]) { printf("主线程(%lu)开始运行...\n", pthread_self()); pthread_t thread_id; pthread_create(&thread_id, NULL, start_routine, NULL); void *retval = NULL; pthread_join(thread_id, &retval); printf("子线程的返回值为:%s\n", (const char *)retval); printf("主线程(%lu)即将退出...\n", pthread_self()); exit(EXIT_SUCCESS); }
-
输出
主线程(140657300412224)开始运行…
子线程(140657300408064)开始运行…
子线程(140657300408064)正在执行,1…
子线程(140657300408064)正在执行,2…
子线程(140657300408064)正在执行,3…
子线程(140657300408064)正在执行,4…
子线程的返回值为:8888
主线程(140657300412224)即将退出…
2 线程取消
2.1 API
int pthread_cancel(pthread_t thread);
发送一个取消请求。目标线程是否响应与什么时候响应依赖于可取消状态
与可取消类型
属性。
2.2 可取消状态
int pthread_setcancelstate(int state, int *oldstate);
可取消状态可通过函数pthread_setcancelstate
函数进行设置。默认为启用。
- 如果线程禁用(
PTHREAD_CANCEL_DISABLE
)了可取消状态属性,则取消请求将保留到可取消状态被启用 - 如果线程启用(
PTHREAD_CANCEL_ENABLE
)了可取消状态属性,则可取消类型决定取消行为什么时候发生
2.3 可取消类型
int pthread_setcanceltype(int type, int *oldtype);
可以取消类型可通过函数pthread_setcanceltype
函数进行设置。可能值为异步
与延迟
。
-
异步(
PTHREAD_CANCEL_ASYNCHRONOUS
)异步的可取消类型意味着可以在任意时刻取消(通常是立即取消,但系统不保证)。
-
延迟(
PTHREAD_CANCEL_DEFERRED
)异步的可取消类型意味着取消被延迟直到下次调用取消点函数
取消点函数列表可通过
man 7 pthreads
进行查询
2.3 取消过程
void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);
当一个取消请求被实施,将按下述步骤进行实施:
- 取消清理函数入栈与调用(
pthread_cleanup_push
) - 线程私有数据的析构函数以不确定顺序的方式被调用
- 终结线程
2.4 案例:取消线程执行
-
源码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> void *start_routine_01(void *ptr) { printf("子线程(%lu)开始运行...\n", pthread_self()); int num = 0; while (1) { printf("子线程(%lu)正在执行,%d...\n", pthread_self(), ++num); sleep(1); } printf("子线程(%lu)即将退出...\n", pthread_self()); return (void *)"8888"; } void *start_routine_02(void *ptr) { printf("子线程(%lu)开始运行...\n", pthread_self()); sleep(3); pthread_cancel(*((pthread_t*)ptr)); printf("子线程(%lu)取消信号已发出\n", pthread_self()); printf("子线程(%lu)即将退出...\n", pthread_self()); return (void *)"9999"; } int main(int argc, char const *argv[]) { printf("主线程(%lu)开始运行...\n", pthread_self()); pthread_t thread_id_01; pthread_create(&thread_id_01, NULL, start_routine_01, NULL); pthread_t thread_id_02; pthread_create(&thread_id_02, NULL, start_routine_02, &thread_id_01); pthread_join(thread_id_01, NULL); pthread_join(thread_id_02, NULL); printf("主线程(%lu)即将退出...\n", pthread_self()); exit(EXIT_SUCCESS); }
-
输出
主线程(140162664855360)开始运行…
子线程(140162664851200)开始运行…
子线程(140162664851200)正在执行,1…
子线程(140162656458496)开始运行…
子线程(140162664851200)正在执行,2…
子线程(140162664851200)正在执行,3…
子线程(140162664851200)正在执行,4…
子线程(140162656458496)取消信号已发出
子线程(140162656458496)即将退出…
主线程(140162664855360)即将退出…