5

我必须处理一个可以从大型项目中的不同位置调用的日志记录模块。我遇到的问题是,有时可以从信号处理程序中执行的代码调用模块。通常,日志记录模块使用 localtime() 和 strftime() 包含时间数据,但当然这些调用不是异步信号安全的,如果从信号处理程序中调用可能会导致死锁。有没有办法(在 GNU/Linux 系统上)来判断我的代码当前是否在信号处理程序上下文中执行,除了例如让每个信号处理程序在处理时设置一个标志?我认为简化我们的信号处理程序会更好,但在这种情况下,我无法选择调用日志模块的位置。

4

3 回答 3

4

首先,您的问题(“我在信号处理程序中吗?”)没有明确的答案。考虑以下代码:

#include <setjmp.h>
#include <signal.h>

jmp_buf jb;
int foo(int s)
{
    longjmp(jb,1);
}

int main()
{
    if (setjmp(jb)) {
        puts("Am I in a signal handler now, or not?");
        return 0;
    }
    signal(SIGINT, foo);
    raise(SIGINT);
}

话虽如此,您可以使用一种技术以对许多程序有意义的方式回答这个问题。选择一个您不打算使用的信号,并将其添加到sa_mask您处理的所有信号中,使用sigaction. 然后您可以使用sigprocmask检查当前信号掩码,如果您指定的信号在信号掩码中,则表示已调用信号处理程序并且尚未返回(返回将恢复原始信号掩码)。

于 2011-09-03T14:04:31.997 回答
4

最简单的方法是通过(命名)管道(写入到 PIPE_MAX 是原子的)或通过 UDP 套接字(同上)记录。消息来源可以由生成消息的函数设置。当然,您需要一个实际读取和处理消息的进程,但它可以保留在信号处理程序的上下文之外。


顺便说一句:您不需要单独的进程来接收消息,您可以将消息发送到您自己的进程并将管道(的读取端)添加到 fd_set (假设您的程序位于选择或轮询循环中),或定期轮询。

于 2011-09-03T14:34:37.910 回答
0

你的系统有sigpending吗?我不知道该函数在信号处理程序期间的行为是什么。但是,如果它返回一个设置标志,那么如果有任何信号未决,您可能会感到悲观并跳过异步不安全调用。

于 2010-03-05T22:05:17.763 回答