【问题标题】:Interrupting c/c++ readline with signals用信号中断 c/c++ readline
【发布时间】:2012-08-30 16:51:44
【问题描述】:

我正在尝试使用信号 (SIGUSR1) 中断 readline,但显然如果未处理信号,程序将退出,在处理时,它会继续 readline,就好像什么都没发生一样。是否应该可以使用信号中断 readline。

我从另一个问题中得到了这个想法:force exit from readline() function

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <readline/readline.h>
#include <pthread.h>

pthread_t main_id;

void *thread_main(void* arg)
{
  sleep(10);
  pthread_kill(main_id, SIGUSR1);
}

void signal_handler(int sig)
{
  puts("got signal");
  (void) sig;
}

int main(int argc, char** argv)
{
  struct sigaction sa;
  sa.sa_handler = signal_handler;
  sa.sa_flags = 0;
  sigemptyset(&sa.sa_mask);
  sigaction(SIGUSR1, &sa, NULL);

  main_id = pthread_self();

  pthread_t id;
  pthread_create(&id, NULL, thread_main, NULL);

  char *input = readline("prompt> ");

  puts("main thread done");
  return 0;
}

输出:

$ ./test
prompt> got signal
enter something
main thread done
$

谢谢。

【问题讨论】:

  • 注意: puts() 在信号处理程序中是不安全的(它可能调用 malloc,它是不可重入的)。
  • 这纯粹是我为测试问题而创建的示例。所以不安全并不重要。
  • 您可能需要使用alternate interface。您还应该阅读更多关于 readlines signal handling.
  • Joachim:使用替代界面效果很好。如果你想领取声望点,请回答我接受,否则我明天做一个。

标签: c pthreads signals readline


【解决方案1】:

Joachim Pileborg 在评论中回答了这个问题。

最好的解决方案似乎是使用 readline 备用界面。文档位于http://www.delorie.com/gnu/docs/readline/rlman_41.html

也是http://www.mcld.co.uk/blog/blog.php?274 的一个非常基本的示例,只需要适应使用 select 而不是使用 sleep 轮询。

比使用信号好多了!

【讨论】:

  • 这个解决方案似乎是最干净的,但是我想知道如何确定是否按下了 ctrl-d、ctrl-c 等?
【解决方案2】:

更改您的 signal_handler 函数:

void signal_handler(int sig)
{
        puts("got signal");
        //(void) sig;
        exit(sig);
}

【讨论】:

  • 我不想直接不干净地退出程序。代码示例纯粹是为了测试问题。我打算在需要大量清理的更大程序中中断 readline,而不仅仅是 exit()。
【解决方案3】:

libreadline 读取字符的默认实现 (int rl_getc(FILE *)) 确实以简单地重新read()ing 的方式处理 EINTR(由read() 返回,如果有信号)。由于这个接收信号并取消readline()

要解决这个问题,您可以将函数指针 rl_getc_function 设置为您自己的实现以读取字符(rl_getc_function 默认指向 rl_getc())。

【讨论】:

  • 我在我发布的示例代码中对此进行了测试,它运行良好,不幸的是我在其他代码中尝试了同样的事情,但它不起作用。我猜那是因为其他代码使用了一个空闲钩子,所以不是阻塞在 rl_getc_function 上,而是阻塞在 select 中并且接受不会中断。我想我得试试 Joachim 提到的备用界面。
  • select()accept() 应该返回接收到的信号并将 errno 设置为 EINTR 两者。因此,您也可以考虑将信号发送到select()(或accept()?我不确定它实际上在做什么)中的线程阻塞。 @TroyHeron
猜你喜欢
  • 2019-06-25
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多