严格的说没有“线程崩溃”,只是触发了SIGSEGV (Segmentation Violation/Fault)。如果没有设置对应的Signal Handler操作系统就自动终止进程(或者说默认的Signal Handler就是终止进程);如果设置了,理论上可以恢复进程状态继续跑(用longjmp之类的工具)
线程有自己的 stack,但是没有单独的 heap,也没有单独的 address space。只有进程有自己的 address space,而这个 space 中经过合法申请的部分叫做 process space。Process space 之外的地址都是非法地址。当一个线程向非法地址读取或者写入,无法确认这个操作是否会影响同一进程中的其它线程,所以只能是整个进程一起崩溃。
1.进程(主线程)创建了多个线程,多个子线程均拥有自己独立的栈空间(存储函数参数、局部变量等),但是多个子线程和主线程共享堆、全局变量等非栈内存。
2.如果子线程的崩溃是由于自己的一亩三分地引起的,那就不会对主线程和其他子线程产生影响,但是如果子线程的崩溃是因为对共享区域造成了破坏,那么大家就一起崩溃了。3.举个栗子:主线程是一节车厢的乘务员,诸多乘客(也就是子线程)就是经过乘务员(主线程)检票确定可以进入车厢的,也就是主线程创建了诸多子线程,每个子线程有自己独立的区域(座位啊啥的),但是诸多乘客和乘务员共享走廊啊卫生间啊等等,如果其中一名乘客座位坏了,摔了(可以认为奔溃了),那么其他乘客和乘务员都不受影响,但是如果乘客将卫生间给破坏了,他也无法使用卫生间(崩溃了),其他乘客和乘务员也不能用卫生间,好吧,那么大家一起憋着吧(崩溃了)。
总体来说,线程没有独立的地址空间,如果崩溃,会发信号,如果没有错误处理的handler,OS一般直接杀死进程。就算是有handler了处理,一般也会导致程序崩溃,因为很有可能其他线程或者进程的数据被破坏了。
实验代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <libgen.h>
#include <assert.h>
#include <stdbool.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <pthread.h>
char* p_ = NULL;
const int pthreadCount_ = 3;
pthread_t pt_[pthreadCount_] = { 0 };
void* threadProc(void* arg)
{
char buf[10] = { 0 };
int pthread_idx_ = *((int*)arg);
sleep(2);
if (pthread_idx_ == 2) {
buf[20] = '0';
p_[0] = '0';
}
while (1) {
printf("thread is %d\n", pthread_idx_);
sleep(2);
}
return NULL;
}
void handler(int sig)
{
printf("The cause the signal is %d\n", sig);
sleep(20);
//exit(-1);
}
int main(int argc, char* argv[])
{
signal(SIGSEGV, handler);
int ret = -1;
int pthread_arg[pthreadCount_] = { 0 };
for (int i = 0; i < pthreadCount_; i++) {
pthread_arg[i] = i;
ret = pthread_create(&pt_[i], NULL, threadProc, &pthread_arg[i]);
if (ret < 0) {
printf("The create thread %d is failed!\n", i);
return 0;
}
}
for (int j = 0; j < pthreadCount_; j++)
pthread_join(pt_[j], NULL);
return 0;
}
运行过程中会在标号为2的线程处因为空指针p的访问而产生segmentation fault。随即整个程序便中断进入信号处理函数,在信号处理函数中sleep 20秒的时间,其他线程在这个过程中任然是运行的。如下图:
但是在实际应用场景中遇到段错误的问题一般是需要退出整个程序进行后续排错处理的,因为bug还是需要改一改的。
————————————————
版权声明:本文为CSDN博主「paradox_1_0」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/paradox_1_0/article/details/105515319