簡體   English   中英

在分段錯誤處理程序中調用 pthread_exit 時終止調用而沒有活動異常

[英]terminate called without an active exception when calling pthread_exit in segmentation fault handler

你好嗎?
我將在 Ubuntu 18.04 上修復工作線程中的分段錯誤。
我的代碼如下。

#include <thread>
#include <signal.h>
#include <string.h>
#include <pthread.h>
#include <opencv2/opencv.hpp>

void sigsegv_handler(int signum, siginfo_t *info, void *data)
{
    printf("The thread was crashed\n");
    pthread_exit(NULL);
}

void sleep_ms(int milliseconds)
{
#ifdef WIN32
    Sleep(milliseconds);
#elif _POSIX_C_SOURCE >= 199309L
    struct timespec ts;
    ts.tv_sec = milliseconds / 1000;
    ts.tv_nsec = (milliseconds % 1000) * 1000000;
    nanosleep(&ts, NULL);
#else
    usleep(milliseconds * 1000);
#endif
}

void thread_func(int i)
{
    if(i == 3)
    {
        int *p = 0;
        *p = 10;
    }
    printf("A new thread ran successfully\n");
}

int main()
{
    /* Set SIGSEGV handler. */
    struct sigaction  handler;
    sigemptyset(&handler.sa_mask);
    handler.sa_sigaction = &sigsegv_handler;
    handler.sa_flags = SA_SIGINFO;
    if (sigaction(SIGSEGV, &handler, NULL) == -1) 
        fprintf(stderr, "Cannot set SIGSEGV handler: %s.\n", strerror(errno));
    int i = 0;
    while(1)
    {
        std::thread writer_thread(thread_func, i);
        writer_thread.detach();
        sleep_ms(1000);
        printf("%d\n", i++);
    }
    return 0;
}

代碼運行良好。
此代碼的 output 如下。
新線程成功運行
0
新線程成功運行
1
新線程成功運行
2
線程崩潰了
3
新線程成功運行
4
新線程成功運行
5
新線程成功運行
6
新線程成功運行
7

但是,如果我將 function "thread_func" 更改如下,程序就會崩潰。

void thread_func(int i)
{
    if(i == 3)
    {
        int *p = 0;
        *p = 10;
    }
    cv::Mat img(100, 100, CV_8UC3); // newly inserted
    cv::resize(img, img, cv::Size(200, 200)); //newly inserted
    printf("A new thread ran successfully\n");
}

錯誤消息如下。

新線程成功運行
0
新線程成功運行
1
新線程成功運行
2
線程崩潰了
在沒有活動異常的情況下調用終止
中止(核心轉儲)

當然,我確信 OpenCV 模塊沒有問題。
你能幫我解決這個問題嗎?
謝謝

簡單的答案是你不能這樣做:

void sigsegv_handler(int signum, siginfo_t *info, void *data)
{
    printf("The thread was crashed\n");
    pthread_exit(NULL);
}

一、按照7.1.4 庫函數的使用,C 11 標准的第 4 段

標准庫中的函數不保證是可重入的,並且可能會修改具有 static 或線程存儲持續時間的對象。

或者,如腳注 188 所述

因此,信號處理程序通常不能調用標准庫函數。

因此,如果您的平台沒有具體保證可以從信號處理程序中安全調用哪些函數,您就不能從信號處理程序中進行任何 function 調用

但是由於您正在調用pthread_exit() ,假設您使用的是 POSIX 系統,POSIX 確實提供了一些關於您可以調用哪些函數的保證,稱為“異步信號安全,在https://pubs.opengroup.org/onlinepubs /9699919799/functions/V2_chap02.html#tag_15_04_03 . Linux 特定列表可在https://man7.org/linux/man-pages/man7/signal-safety.7.ZFC35FDC70D5FC69D7A53EZ2

請注意, printf()pthread_exit()都不在 list 中

SIGSEGV信號處理程序中調用printf()將是危險的 - 大多數printf()實現將使用某種形式的malloc() / free() ,而SIGSEGV通常是malloc() / new / free()的結果free() / delete操作遇到損壞的堆。 堆操作往往在某種鎖定下發生,以防止同時修改堆 state,因此在所有事物的SIGSEGV處理程序中調用printf()會產生巨大的死鎖風險。

而且pthread_exit()也會造成巨大的問題——它不僅試圖改變進程地址空間中的進程 state,它還試圖改變 Z50484C19F1AFDAF3841EDA0D8D8 空間中的進程 state。 在信號處理程序中,這根本行不通。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM