【问题标题】:sigset: ignoring ctrl-c in Unixsigset:在 Unix 中忽略 ctrl-c
【发布时间】:2010-09-07 22:23:54
【问题描述】:

我试图让我的程序在 unix 中忽略 Ctrl+C 这似乎有效,问题是它一直在写“语法错误”。这是代码

extern "C" void ignore( int sig )
{            
    fprintf( stderr, "\n"); // Print a new line
    // This function does nothing except ignore ctrl-c
}

int main()
{           
    // For ctrl-c
    sigset( SIGINT, ignore );

    while (1) {
        getUserInput();
    }      

    return 0;
}

每次我点击 Ctrl+C 时,它都会再次运行 getUserInput,这是预期的行为,但它也会写入“语法错误”。我检查并执行了“忽略”功能,一旦执行,它就会打印错误消息,我不知道为什么。

请问大家有什么线索吗?

非常感谢,

杰瑞

【问题讨论】:

  • 如果这是 C,为什么是 extern "C"?
  • 请发布一个完整的、独立的、可以编译的程序。我在这里至少看到两件事可能是你的问题,但如果没有完整的测试用例,我无法确定。
  • 如果这是新代码,你可能想使用sigaction; sigset 是 pre-POSIX 并且已弃用
  • 谢谢迈克尔,很遗憾这段代码将在一台旧的 Solaris 机器上运行,所以我必须使用 sigset。

标签: c unix


【解决方案1】:

不要使用sigset()。虽然它在 POSIX 2008 中,但它被标记为过时的 - 在线程程序中也是不安全的。

然后您可以在signal() 和sigaction() 之间进行选择,signal() 受到 ISO C 的支持,但有一些不受欢迎的特性,这是 POSIX 系统中的首选解决方案。

信号处理的一个关键点是确保您在进入程序时不会捕获任何被忽略的信号 - 除非您知道调用者无法知道的某些内容(例如您需要为死去的孩子捕获 SIGCHLD 信号) .

这导致了自古以来就为signal() 宣传的标准公式:

if (signal(SIGINT, SIG_IGN) != SIG_IGN)
    signal(SIGINT, ignore);

或者,对于sigaction():

struct sigaction new_sa;
struct sigaction old_sa;
sigfillset(&new_sa.sa_mask);
new_sa.sa_handler = SIG_IGN;
new_sa.sa_flags = 0;

if (sigaction(SIGINT, &new_sa, &old_sa) == 0 && old_sa.sa_handler != SIG_IGN)
{
    new_sa.sa_handler = ignore;
    sigaction(SIGINT, &new_sa, 0);
}

由于您没有向我们展示getUserInput() 函数,我们无法预测您看到“语法错误”的原因。但是,如果你有一个语法在起作用,很可能是你的读取没有返回有效数据,并且解析器对缓冲区中剩下的内容不满意。

【讨论】:

  • 感谢您的信息。确实,getUserInput 是一个很大的语法在起作用,我相信你是对的。谢谢!
【解决方案2】:

(注意:为了提高可移植性,您可能应该使用signal()(C 标准库)或sigaction()(POSIX)而不是sigset(),但我认为这不是问题所在。)

你并没有真正忽略这里的信号;您正在捕捉它并采取自己的行动 - 但系统调用可能由于中断而返回错误。

例如也许您已经导致read 系统调用以EINTR 失败。我怀疑真正的问题是getUserInput() 中的某些代码没有处理这种错误情况。

您可以通过将处理程序设置为特殊值SIG_IGN 来完全忽略该信号,该值应适用于sigset()、signal() 或sigaction() 中的任何一个。

【讨论】:

    【解决方案3】:

    “语法错误”消息必须来自 getUserInput 函数(当然也可以是它调用的函数)——您可以通过让该函数打印出它接收到的内容以及它抱怨的原因来进行调查。

    请注意,忽略信号的规范方法是使用预定义的SIG_IGN 作为信号处理程序。例如 sigset(SIGINT, SIG_IGN)

    【讨论】:

      【解决方案4】:

      ignore() 做的比什么都不做。

      当您在 UNIX 上运行此代码时,SIGINT 在执行 getUserInput() 的同一线程上异步传递。如果SIGINT 在getUserInput() 访问stderr 时到达,则行为未定义,因为fprintf() 通常不设计为可重入的。 (但是,该行为可能包括乱码和/或重复输出。您的程序是否在 SIGINT 交付之前打印了“语法错误”?)CERT 和 GNU libc 有更多关于此的信息。

      如果您在 Win32 上运行此代码,SIGINT 将异步传递 in a separate thread。

      【讨论】:

        猜你喜欢
        • 2016-05-01
        • 2020-05-12
        • 1970-01-01
        • 2019-06-05
        • 1970-01-01
        • 1970-01-01
        • 2021-12-19
        • 1970-01-01
        • 2011-10-18
        相关资源
        最近更新 更多