2011-06-16 204 views
1

下面的程序为整个进程设置SIG_ALRM处理程序,创建一个线程,并将SIG_ALRM信号发送到新创建的线程。 在SIG_ALRM处理函数中调用pthread_exit。 结果 - 分段错误。 如果您在发送信号之前入睡 - 确定。pthread_exit在信号处理程序中导致段错误

看起来新线程在pthread_exit时刻还没有启动。 我试图用gdb定位段错误,但无法用gdb重现崩溃。

什么导致分段错误?

谢谢!

#include <signal.h> 
#include <pthread.h> 
#include <iostream> 
#include <cassert> 
using namespace std; 

void* threadFunc(void* arg) { 
    cout << "thread: started. sleeping..: " << pthread_self() << endl; 
    sleep(10); 
    cout << "thread: exit" << endl; 
    return NULL; 
} 

void alrm_handler(int signo) { 
    cout << "alrm_handler: " << pthread_self() << endl; 

    pthread_exit(NULL); //if comment - no segmentation fault 
} 

int main() { 
    cout << "main: " << pthread_self() << endl; 

    struct sigaction act; 
    act.sa_handler = alrm_handler; 
    act.sa_flags = 0; 
    sigemptyset(&act.sa_mask); 
    sigaction(SIGALRM, &act, NULL); 

    pthread_t t; 
    int rc = pthread_create(&t, NULL, threadFunc, NULL); 
    assert(rc == 0); 

// usleep(1000); //if Uncomment - no segmentation fault 
    rc = pthread_kill(t, SIGALRM); 
    assert(rc == 0); 

    pthread_join(t, NULL); 

    cout << "main: exit" << endl; 
    return 0; 
} 

输出:

主:140130531731232
alrm_handler:140130504095488
分段故障

回答

1

给线程初始化变化过程完成。所以只需取消注释下面的行是正确的方法。

usleep(1000); 
+0

Johh,你有没有任何参考,这明确表示?谢谢! – Ayrat 2011-06-16 20:25:13

+0

@Ayrat:我找不到一个。但我只是用核心转储进行分析。由于线程尚未启动(因此可能无法完全初始化),程序将以'SIGSEGV'退出。 – 2011-06-17 04:20:21

4

pthread_exit不是异步信号安全的。除非您确定信号处理程序不中断异步信号不安全功能,否则不能从信号处理程序调用它。特别是,调用pthread_create和新线程启动函数的入口之间的时间必须被认为是同步信号不安全的 - 这在标准中从未明确说明,但您可以将新线程视为仍在“pthread_create “(这是异步信号不安全),如果你喜欢。

+0

是的,我摆脱了在signal_handler中调用丑陋的退出。)谢谢R ..! – Ayrat 2011-07-12 15:16:46