c - pthread_cancel 后的分段错误
问题描述
在我的程序中,我有两个线程,一个计算一些递归函数,另一个显示“进度点”,因为第一个线程进行计算。有代码:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#define test_errno(msg) do{if (errno) {perror(msg); exit(EXIT_FAILURE);}} while(0)
void *progressDotsThread(void* _arg){
for(int i=0;;i++){
printf(".");
fflush(stdout);
sleep(1);
}
}
void *seriesCalculateThread(void* n){
int result;
if((long)n==1) return (void*)(1);
else if((long)n==2) return (void*)(-5);
else{
int nmin1 = (long)seriesCalculateThread( (void*) ( (long)n -1 ));
int nmin2 = (long)seriesCalculateThread( (void*) ( (long)n -2 ));
result = nmin1*((long)n)*nmin2;
return (void*)(result);
}
}
int main(void) {
long n=0;
int result =0;
pthread_t w1,w2;
printf("Give n\n");
scanf ("%d",&n);
if(n<1){
printf("Value must be higher than 0");
}
else{
errno= pthread_create(&w2,NULL,seriesCalculateThread,(void *)n);
test_errno("pthread_create");
errno= pthread_create(&w1,NULL,progressDotsThread,NULL);
test_errno("pthread_create");
if(!pthread_join(w2,(void**)&result)){
errno = pthread_cancel(w1); //<--- Where segmentation fault happens
test_errno("pthread_cancel");
}
printf("%d\n", result);
}
return EXIT_SUCCESS;
}
我pthread_create
是他们两个,然后是我if(!pthread_join)
做计算的那个,当计算完成时,我取消显示点的那个。
if(!pthread_join(w2,(void**)&result)){
errno = pthread_cancel(w1); //<--- Where segmentation fault happens
test_errno("pthread_cancel");
}
我这样做了,尽管在调用 pthread_cancel(w1) 后出现分段错误,但我不知道为什么会发生这种情况。
我尝试使用终端编译它gcc -g -Wall -pthread psthreadss.c -lpthread
,但它的效果不如在 Eclipse 中好。如果这很重要,我会使用 Ubuntu 18.04。
解决方案
然后我
if(!pthread_join)
进行计算,当计算完成时,我取消显示点的那个。
您的程序有一个逻辑错误和一个内存损坏错误。
逻辑错误:您假设这!pthread_join
意味着计算已完成。这不是那个意思。仅当您使用不正确的参数(线程 ID未知、尚未启动或已加入)调用它时才pthread_join
返回非零状态。w2
您的代码应如下所示:
int rc = pthread_join(w2, ...);
assert(rc == 0);
rc = pthread_cancel(w1);
assert (rc == 0);
关于内存损坏错误:在 64 位系统上(我假设您正在使用)sizeof(int) == sizeof(result) == 4
,但是sizeof(void*) == 8
.
这段代码:
int result =0;
...
pthread_join(w1, (void**)&result)
获取一个 4-byte 的地址result
,并要求pthread_join
在其中存储一个 8-byte 的值。可预测的结果是堆栈损坏。
我不知道这究竟是如何触发的SIGSEGV
,但是一旦你的程序中有未定义的行为,所有的赌注都会被取消。
要解决此问题,请将result
类型更改为intptr_t
. 我希望在修复后崩溃会消失。
您还应该尝试使用 Address Sanitizer:gcc -fsanitize=address -g ...
在进行任何更改之前。它很有可能会告诉您有关堆栈溢出的信息。
推荐阅读
- bash - 如何将 bash 脚本插入 Hocon 变量
- macos - 在 mac os x 上以编程方式简单的 Spark 启动
- python - 如何增加熊猫系列中截断的显示行数
- sql - 如何使用似乎忽略索引的窗口函数提高查询的性能?
- python - 如何在python中创建一个具有多个数组的单个数组?
- android - 如何使用 Retrofit 调用 Json
- javascript - 退出 AJAX 循环或在 html 页面列表中查找 alt 以进行比较
- reporting-services - SSRS 特定字符串的颜色格式
- vba - 使用 Me 时,从数据源中选择的表单上的字段不可用
- python - 提取 .txt 文件中两个关键字之间的所有单词