gpt4 book ai didi

c++ - 为什么我收到信号时会出现段错误

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:36:36 27 4
gpt4 key购买 nike

我在处理信号 SIGALARM 时遇到段错误。

这是我的代码。

class UThread{
public:
UThread(){}
~UThread(){
signal(SIGALRM,SIG_IGN);
for(size_t i=0;i<thread_list.size();i++){
delete thread_list[i]->uc_stack.ss_sp;
delete thread_list[i];
thread_list[i]=NULL;
}
}
int create_thread(void (*callback)(void *),void *args){
ucontext_t *new_context= new ucontext_t;

assert(getcontext(new_context) != -1);
new_context->uc_stack.ss_sp=new char[1024];
new_context->uc_stack.ss_size=1024;
new_context->uc_flags=0;
new_context->uc_link=0;
assert(new_context->uc_stack.ss_sp!=NULL);

makecontext(new_context,(void (*)())callback,1,args);//make a context
size_t n=thread_list.size();

//find a position to save the pointer.
int i=0;
for(;i<n;i++){
if(thread_list[i]==NULL)
break;
}
if(i<n)
thread_list[i]=new_context;
else{
thread_list.push_back(new_context);
}
return i;
}

void start_thread(){
ucontext_t *main_context= new ucontext_t;
getcontext(main_context);
thread_list.push_back(main_context);

struct sigaction sa;
sa.sa_handler=schedule;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask,SIGALRM);
sigaction(SIGALRM,&sa,NULL);

struct itimerval tick;
tick.it_value.tv_sec = 0;
tick.it_value.tv_usec = 1;

tick.it_interval.tv_sec = 0;
tick.it_interval.tv_usec = 1000;//send a SIGALRM
setitimer(ITIMER_REAL,&tick,NULL);
}

private:
static void schedule(int signo){//deal with the signal
int last_id=current_id;
int n=thread_list.size();

int i=rand()%n;//get a random number.
while(thread_list[i]==NULL){
i=rand()%n;
}
current_id=i;
if(thread_list[last_id]==NULL){//if it has been cancelled,just setcontext.
setcontext(thread_list[i]);
return;
}
swapcontext(thread_list[last_id],thread_list[current_id]);//swap the context.
}

static int current_id;
static vector<ucontext_t*> thread_list;
};
vector<ucontext_t*> UThread::thread_list;
int UThread::current_id=0;

这是类定义的内容。如果我调用两个以上的函数,它将出现段错误。

void f2(void *){
const char *buf="I am f2.\n";;
while(true){
write(STDOUT_FILENO,buf,strlen(buf));
}
}

void f3(void *){
const char *buf="I am------- f3.\n";
while(true){
write(STDOUT_FILENO,buf,strlen(buf));
}
}

int main(){
UThread t;
t.start_thread();
int thread_id2=t.create_thread(f2,NULL);
int thread_id3=t.create_thread(f3,NULL);
const char *buf="I am main.\n";
while(true){
write(STDOUT_FILENO,buf,strlen(buf));
}
return 0;
}

这是函数调用

如果我在主函数中删除一个t.create_thread(f3,NULL);,它会成功运行,没有错误。但是如果我添加两个t.create_thread(func, NULL); 到 main 函数,在 swapcontext(thread_list[last_id],thread_list[current_id]); 完成后会出现段错误。

最佳答案

显示的代码安装了一个信号处理程序:

    struct sigaction sa;
sa.sa_handler=schedule;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask,SIGALRM);
sigaction(SIGALRM,&sa,NULL);

schedule() 函数尝试访问各种 C++ 库容器,并调用它们的方法:

static void schedule(int signo){//deal with the signal
int last_id=current_id;
int n=thread_list.size();

此处的thread_list 引用是一个std::vector

没有一个 C++ 库容器是信号安全的。试图在信号处理程序中访问它们是未定义的行为。你的段错误是必然的结果。最重要的是,信号处理程序唯一可以安全地做的事情就是调用有限数量的系统调用。它甚至不能调用 mallocnew。这不仅适用于 SIGALRM,而且适用于任何信号。

底线是您在信号处理程序中尝试做的任何事情都无法完成。

您表示您使用的是 Linux。 signal-safety(7) Linux 手册页列出了您可以从信号处理程序进行的唯一系统调用。如果系统调用不在列表中,则不能从信号处理程序中调用它。请注意,该列表中没有与 C++ 相关的内容。 C++ 库中没有任何东西是信号安全的。就是这样,故事结束,句号。

但是,在 Linux 上,有一种方法可以安全地处理信号,在 C++ 代码中使用 signal file descriptors .查看该手册页的内容,也许您可​​以调整您的代码以使用信号文件描述符。

关于c++ - 为什么我收到信号时会出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48273540/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com