在Linux环境中,C程序如何在同时执行其他操作的同时轮询用户输入?

在Linux环境中,C程序如何在同时执行其他操作的同时轮询用户输入?,c,linux,C,Linux,背景: 我是一个相对缺乏经验的开发人员,试图编写与PCI运动控制器接口的软件。我在UbuntuLinux18.04上使用C(用gcc编译) 我正在编写的程序需要定期检查运动控制器发送的未经请求的状态消息(大约每秒一次),并在终端屏幕上显示它找到的任何消息(我正在使用ncurses库) 我所拥有的: 现在,为了做到这一点,我调用了一个函数,该函数在while循环中检查未经请求的消息。代码大致类似于: while (1) { // check for messages from PCI an

背景:

我是一个相对缺乏经验的开发人员,试图编写与PCI运动控制器接口的软件。我在UbuntuLinux18.04上使用C(用gcc编译)

我正在编写的程序需要定期检查运动控制器发送的未经请求的状态消息(大约每秒一次),并在终端屏幕上显示它找到的任何消息(我正在使用
ncurses
库)

我所拥有的:

现在,为了做到这一点,我调用了一个函数,该函数在while循环中检查未经请求的消息。代码大致类似于:

while (1)
{
    // check for messages from PCI and store them in a traffic buffer
    checkForMessages(PCIconnection, trafficBuffer);

    // output the traffic buffer to the screen
    printf("%s", trafficBuffer);    
}
我需要什么:

我需要以允许用户结束循环的方式提示用户输入。例如,用户可以输入
end
,导致循环停止,程序继续

问题:

我不知道有什么方法可以在不将
fgets
放入while循环的情况下实现这一点,从而导致程序停止并等待用户在每次循环迭代中输入一些内容

我已经寻找了一个解决方案,但是我还没有找到关于如何实现我需要的功能的讨论。打开一个新线程或进程似乎是朝着正确方向迈出的一步

如果我目前所做的是糟糕的实践,我愿意完全重构我的代码


谢谢你的帮助

简单的答案是多线程,即部署线程等待用户输入,同时继续循环。因此,我们有:

char flag = 1;

while (flag) {
     // run the loop

     // if thing happens deploy the thread which will ask user for input

}
我已经有一段时间没有写线程了,我想这一页比我向你们解释要好:

您的任务需要基于
选择
epoll
。它将等待的一个事件是用户输入-当
STDIN\u FILENO
准备好读取时。另一个是需要轮询控制器时的1秒周期计时器

有相当多的库为您实现了一个事件循环,这样您就可以专注于需要处理哪些事件以及如何处理。是最古老、功能丰富且受欢迎的系统之一。

我认为“Unix”的方式不是要求用户输入,而是对用户信号做出反应。例如,当用户按下Ctrl-C时,当前正在运行的进程将收到SIGINT

可以找到如何正确使用SIGINT中断循环的示例。如果链接过时,将其复制到答案中:

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static volatile sig_atomic_t got_signal = 0;

static void my_sig_handler(int signo)
{
    got_signal = 1;
}

int main()
{
    struct sigaction sa;

    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = &my_sig_handler;
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction");
        return EXIT_FAILURE;
    }

    for (;;) {
        if (got_signal) {
            got_signal = 0;
            printf("Received interrupt signal!\n");
        }
        printf("Doing useful stuff...\n");
        sleep(1); /* Sleep is not only useful, it is essential! */
    }
    return EXIT_SUCCESS;
}
#包括
#包括
#包括
#包括
#包括
静态易失性sig_原子信号=0;
静态void my_sig_处理程序(int signo)
{
got_信号=1;
}
int main()
{
struct-sigaction-sa;
memset(&sa,0,sizeof(struct-sigaction));
sa.sa_handler=&my_sig_handler;
if(sigaction(SIGINT,&sa,NULL)=-1){
佩罗尔(“sigaction”);
返回退出失败;
}
对于(;;){
如果(得到信号){
got_信号=0;
printf(“接收到的中断信号!\n”);
}
printf(“做有用的事情…\n”);
睡眠(1);/*睡眠不仅有用,而且是必不可少的*/
}
返回退出成功;
}

(在您的情况下,最好将
break;
放入
if
块中,或者在(!got_signal)
时使用

但请参阅以了解有关多线程的一些注意事项。是的,在那篇文章发布到accu通用邮件列表
accu之前,我对多线程涉及的地方和陷阱没有多少感觉-general@accu.org
。它对验证多线程代码的固有缺陷提出了一些很好的观点。@DavidC.Rankin我想在我的答案中包含链接,但它似乎不起作用。该死,我讨厌网站破坏它们的旧链接。他们完全重拨了他们的网站,所有超载的问题现在都可以在找到,并且保持链接在那里。谢谢你的回答!这绝对是对我所问问题的有效回答,所以我接受了。经过更多的阅读,我还发现
ncurses
本身就有一个答案。调用函数
timeout
并传递它
0
使
getch
(一个
ncurses
输入函数)无阻塞,这也解决了我的问题。问题是,你可能有一个繁忙的等待循环,占用你100%的cpu时间,除非你使用某种类型的睡眠,这使得在大多数情况下对输入的响应不是即时的
select
/
poll
,或者基于这些的库,几乎肯定会有较少的不良副作用。