到目前为止,我还没有找到解决类似情况的帖子:
在用于某些浮点数据集超声处理的命令行unix程序中,我有一个main()
,它可以读取来自名称为program argumant或stdin
重定向( < )
的文件或来自其他程序( | )
的数据,具体取决于argc
。
只要argv[1]
是文件名,我就可以通过点击&#39;输入&#39;来轻轻地停止执行。 key,以编程方式设置淡出信号的条件,清理并定期退出音频子例程并终止程序。我通过调用非阻塞kbhit()
的函数来实现它。定义:
int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec = 0;
tv.tv_usec= 0;
FD_ZERO(&read_fd);
FD_SET(0, &read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
return 0;
if(FD_ISSET(0, &read_fd))
return 1;
return 0;
}
但是,如果正在重定向或管道输入,则kbhit()
会阻止执行,因为它会在启动时停止播放,因为它会返回1
。我不知道如何处理它,所以我使用的是SIGINT,我觉得它不那么优雅。以下是代码段:
//... ...
bool stop = false; //global variable
//... ...
if(argc == 1) stdr = true;//flag: reading from redirected or piped stdin (simplified)
//code for reading from file or stdin, using fscanf() ...
//code for initializing and starting audio process ...
//loop, during audio callback on a separate thread ...
while((player.totalFrames < player.totalSize) && !stop){
if(!stdr){ //( = reading from file)
if (kbhit()){
stop = true;
break;
}
}else{ //( = reading from redirected stdin)
if (signal(SIGINT, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGINT\n");
}
}
if(stop){ … }//code for gently fading the signal and stopping the audio process
//cleanup and termination...
//... ...
这是标准信号处理程序,它将stop
条件设置为true
:
void sig_handler(int s)
{
if (s == SIGINT){
if(debug)printf("\ncaught SIGINT\n");
stop = true;
}
}
是否有更优雅的方式:
如何从代理键盘(在重定向或管道中)允许这样的消息的代码如何? kbhit()
内的论据是否可能以某种方式重新排列,或者必须朝着完全不同的方向发展。我不知道哪个?
如果可以的话,我会很感激的建议。提前致谢!
答案 0 :(得分:1)
如果您希望交互式TTY用户能够使用输入字符(不是导致TTY驱动程序发送信号的信令字符)来停止程序,并且该程序必须重定向,那么您唯一的选择就是显式打开文件描述符到TTY设备(通过/dev/tty
)并监视 输入。
您的kbhit
函数可能应该使用int fd
参数,使用该参数为其提供应该轮询的打开TTY文件描述符。
如果您希望TTY的单个字符输入立即可用于程序(即使该字符不是换行符),则必须将TTY置于“原始模式”,或者至少部分:至少,您必须通过否定ICANON
结构中c_iflag
数字字段中的struct termios
标记来禁用“规范输入处理”,并确保c_cc[VTIME]
和c_cc[VMIN]
分别设置为0和1。查看tcgetattr
和tcsetattr
。您可能希望禁用信令字符,并禁用回显和其他内容。某些平台具有cfmakeraw
函数,可以以正确的方式调整struct termios
对象,从而实现非常原始的模式,而不必使用任何termios
标记。
在规范输入处理模式下,TTY不会使进程可用输入(并且在输入的select
下不会选择正数),直到收到完整的输入行为止。
答案 1 :(得分:1)
您的问题是,从重定向读取数据时,您尝试同时使用文件和键盘。 stdin不再是你的键盘,它是文件,因此你无法从键盘读取数据(如按下“enter”键)。
如果我没弄错的话,你只有两个选项是信号,并为键盘输入(TTY)打开一个新的文件描述符。