我想在收到SIGUSR1时使用ungetc将'A'字符填回stdin。想象一下,我有充分的理由这样做。
当调用foo()时,stdin中的阻塞读取不会被接收到信号时的ungetc调用中断。虽然我没想到这会按原样运作,但我想知道是否有办法实现这一目标 - 有没有人有建议?
void handler (int sig) { ungetc ('A', stdin); } void foo () { signal (SIGUSR1, handler); while ((key = fgetc (stdin)) != EOF) { ... } }
答案 0 :(得分:5)
不是试图通过信号让ungetc()
取消阻止阻塞fgetc()
调用,也许您可以尝试不使用fgetc()
阻止开始并等待stdin上的活动{ {1}}。
默认情况下,终端设备的线路规则可能在规范模式下工作。在此模式下,终端驱动程序不会向用户空间显示缓冲区,直到看到换行符(按下 Enter 键)。
要完成您想要的操作,您可以使用select()
操作tcsetattr()
结构,将终端设置为原始(非规范)模式。这应该是阻止调用termios
立即返回用fgetc()
插入的字符。
ungetc()
注意:为简单起见,此代码省略了错误检查。
清除
void handler(int sig) {
/* I know I shouldn't do this in a signal handler,
* but this is modeled after the OP's code.
*/
ungetc('A', stdin);
}
void wait_for_stdin() {
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fileno(stdin),&fdset);
select(1, &fdset, NULL, NULL, NULL);
}
void foo () {
int key;
struct termios terminal_settings;
signal(SIGUSR1, handler);
/* set the terminal to raw mode */
tcgetattr(fileno(stdin), &terminal_settings);
terminal_settings.c_lflag &= ~(ECHO|ICANON);
terminal_settings.c_cc[VTIME] = 0;
terminal_settings.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &terminal_settings);
for (;;) {
wait_for_stdin();
key = fgetc(stdin);
/* terminate loop on Ctrl-D */
if (key == 0x04) {
break;
}
if (key != EOF) {
printf("%c\n", key);
}
}
}
和ECHO
标志会分别在键入字符时禁用字符回显,并直接从输入队列中满足读取请求。在ICANON
数组中将VTIME
和VMIN
的值设置为零会导致读取请求(c_cc
)立即返回而不是阻止;有效地轮询stdin。这会导致fgetc()
设置为key
,因此需要另一种终止循环的方法。通过使用EOF
等待stdin上的活动,可以减少对stdin的不必要轮询
执行程序,发送select()
信号并输入
t e s t 导致以下输出 1 :
A t e s t
1)在Linux上测试
答案 1 :(得分:1)
目标并不完全清楚,但这正是你要找的吗?
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
int handle = 0;
void handler (int sig) {
handle = 1;
}
void foo () {
int key;
signal (SIGUSR1, handler);
while ((key = fgetc (stdin)) != EOF) {
printf("%c\n",key);
if (handle) {
handle = 0;
ungetc('A',stdin);
}
}
}
int main(void) {
printf("PID: %d\n",getpid());
foo();
}
它产生这个输出:
PID: 8902
test (typed on stdin)
t
A
e
s
t
答案 2 :(得分:1)
FILE * s不是异步安全的。
您不能在信号处理程序中操作FILE *,而其他人也使用相同的FILE *。你可以在信号处理程序中使用的函数在这里说明:
http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html。 (有可能 在Windows机器上有所不同,但是任何文件*都不安全。
答案 3 :(得分:1)
这与@ Jamie的答案基本相同,略有改动以支持您在A
之前处理t
的愿望,但是在代码框中输入代码太难了,所以我'我们分别发布了这个答案。
int insert_an_A = 0;
void handler(int sig) { insert_an_A = 1; }
void process_char(char c) { ... }
int main(int argc, char **argv) {
int c;
/* skip signal setup */
while ((c = fgetc(stdin)) != EOF) {
if (insert_an_A) {
process_char('A');
insert_an_A = 0;
}
process_char(c);
}
}
如果要处理在返回fgetc
的{{1}}期间收到的处理程序,则还应在退出while循环后检查EOF
。
另请注意,通常信号处理程序的最佳实践是设置全局变量并从处理程序返回。在你的程序的其他地方,寻找变量并做出适当的反应。