我正在尝试取消来自调用方或被调用方的线程,但是两者都导致程序崩溃
但是如果我加入,我将获得正确的退出状态。
如何正确收集pthread_cancel
上的退出状态
手册页如下
被取消的线程终止后,使用pthread_join(3)获得PTHREAD_CANCELED作为线程的退出状态。(加入线程是知道取消具有已完成。)
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg);
int errNum = 3;
int main()
{
pthread_t t_id;
void *status;
// on success pthread_create return zero
if(pthread_create(&t_id,NULL,thread_func,NULL) != 0){
printf("thread creation failed\n");
return 0;
}
printf("thread created with id %u successfully\n",t_id);
// status will be collecting the pthread_exit value
// error numberis returned incase of error
// pthread_cancel(t_id);
if(pthread_join(t_id,&status) != 0){
printf("join failed\n");
}
printf("thread %u exited with code %d\n", t_id, *(int *)status);
return 0;
}
void *thread_func(void *arg)
{
printf("Inside thread_func :%u\n",pthread_self());
//the arguments of pthread_exit should not be from local space, as it will be collected in caller using join
//pthread_exit(&errNum);
// if we return it may cause seg fault as we are trying to print the value from ptr(status)
//return ;
pthread_cancel(pthread_self());
}
如果取消线程(在正常终止之前),那么当您加入它时,您将收到PTHREAD_CANCELED
作为线程的返回值/退出状态。该宏扩展为返回的实际void *
值,因此您可以将接收到的值直接与该值进行比较,以判断线程是否被取消。通常,它不是valid指针,因此您不得尝试取消引用它。
示例:
void *status;
// ...
if (pthread_join(t_id, &status) != 0) {
// pthread_join failed
} else if (status == PTHREAD_CANCELED) {
// successfully joined a thread that was cancelled
// 'status' MUST NOT be dereferenced
} else {
// successfully joined a thread that terminated normally
// whether 'status' may be dereferenced or how else it may be
// used depends on the thread
}
值得注意的是,Linux手册页的措辞有点快速和松散。从进程的意义上讲,线程不具有“退出状态”,并且实际的POSIX规范在线程上下文中不使用该术语。例如,the POSIX specifications for pthread_join()
说:
[成功返回带有非NULL
pthread_join()
参数的pthread_join()
调用后,终止线程传递给value_ptr
的值应在pthread_exit()
引用的位置可用。
与Linux的措辞相比,这有点令人mouth舌,但它被选择为非常精确。
也请注意,此处选择value_ptr
类型是有意且有用的。打包void *
不仅是一种钝器。通过这样的指针,线程可以提供对任何类型对象的访问,这对于传达有关其计算结果的信息可能是有用的。另一方面,线程避开这种可能性并只返回int
是相当普遍的。但是,如果线程确实希望以这种方式提供整数代码,则它很可能会提供NULL
值cast to类型int
,而不是指向包含以下内容的void *
类型对象的指针选择的值。在这种情况下,可以通过强制返回int
而不是通过取消引用指针来获取值。