我可以让 ungetc 取消阻止阻塞的 fgetc 调用吗?
我想在收到 SIGUSR1 后使用 ungetc 将“A”字符重新填充到标准输入中。想象一下我有充分的理由这样做。
调用 foo() 时,stdin 中的阻塞读取不会因收到信号后的 ungetc 调用而中断。虽然我没想到它会按原样工作,但我想知道是否有办法实现这一目标 - 有人有建议吗?
void handler (int sig) { ungetc ('A', stdin); } void foo () { signal (SIGUSR1, handler); while ((key = fgetc (stdin)) != EOF) { ... } }
I would like to stuff an 'A' character back into stdin using ungetc on receipt of SIGUSR1. Imagine that I have a good reason for doing this.
When calling foo(), the blocking read in stdin is not interrupted by the ungetc call on receipt of the signal. While I didn't expect this to work as is, I wonder if there is a way to achieve this - does anyone have suggestions?
void handler (int sig) { ungetc ('A', stdin); } void foo () { signal (SIGUSR1, handler); while ((key = fgetc (stdin)) != EOF) { ... } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
与其尝试通过信号让
ungetc()
解锁阻塞的fgetc()
调用,也许您可以尝试不使用fgetc()
使用select()
阻止开始并等待标准输入上的活动。默认情况下,终端设备的线路规则可以工作在规范模式下。在此模式下,终端驱动程序不会将缓冲区呈现给用户空间,直到看到换行符(按下 Enter 键)。
要完成您想要的任务,您可以使用
tcsetattr()
操作termios
结构。这应该阻止对fgetc()
的调用,以立即返回使用ungetc()
插入的字符。注意:为简单起见,此代码省略了错误检查。
分别清除
ECHO
和ICANON
标志会禁用键入字符时的回显,并导致直接从输入队列满足读取请求。将c_cc
数组中的VTIME
和VMIN
值设置为零会导致读取请求 (fgetc()
)立即返回而不是阻塞;有效地轮询标准输入。这会导致key
设置为EOF
,因此需要另一种终止循环的方法。通过使用select()
等待标准输入上的活动,可以减少不必要的标准输入轮询。执行程序,发送
SIGUSR1
信号,然后输入t e s t 产生以下输出1:
1 )在 Linux 上测试
Rather than try to get
ungetc()
to unblock a blockingfgetc()
call via a signal, perhaps you could try not havingfgetc()
block to begin with and wait for activity on stdin usingselect()
.By default, the line discipline for a terminal device may work in canonical mode. In this mode, the terminal driver doesn't present the buffer to userspace until the newline is seen (Enter key is pressed).
To accomplish what you want, you can set the terminal into raw (non-canonical) mode by using
tcsetattr()
to manipulate thetermios
structure. This should case the blocking call tofgetc()
to immediately return the character inserted withungetc()
.NOTE: This code omits error checking for simplicity.
Clearing the
ECHO
andICANON
flags respectively disables echoing of characters as they are typed and causes read requests to be satisfied directly from the input queue. Setting the values ofVTIME
andVMIN
to zero in thec_cc
array causes the read request (fgetc()
) to return immediately rather than block; effectively polling stdin. This causeskey
to get set toEOF
so another method for terminating the loop is necessary. Unnecessary polling of stdin is reduced by waiting for activity on stdin usingselect()
.Executing the program, sending a
SIGUSR1
signal, and typingt e s t results in the following output1:
1) tested on Linux
目前尚不完全清楚您的目标是什么,但这就是您正在寻找的吗?
它产生以下输出:
It is not entirely clear what your goal is, but is this what you are looking for?
It produces this output:
FILE* 不是异步安全的。
当其他人也使用同一个 FILE* 时,您不能在信号处理程序中操作 FILE*。您可以在信号处理程序中使用的所有功能如下:
http://www. opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html 。 (这可能是
在 Windows 机器上有所不同,但任何 FILE* 在那里也不安全。
FILE*s are not async safe.
You cannot operate on a FILE* in a signal handler while someone else also uses that same FILE*. functions you can all in a signal handler is stated here:
http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html . (It might be
different on a windows machine, but still any FILE* are not safe there either.
这本质上与 @Jamie 的答案相同,稍作更改以支持您在
t
之前处理A
的愿望,但在注释框中键入代码太难了,所以我单独发布了这个答案。如果您想要处理在调用
fgetc
期间收到的返回EOF
的处理程序,您还应该在退出 while 循环后检查insert_an_A
。另请注意,通常信号处理程序的最佳实践是设置全局变量并从处理程序返回。在程序的其他地方,寻找变量的变化并做出适当的反应。
This is essentially the same as @Jamie's answer, slightly changed to support your desire to process the
A
before thet
, but it's too hard to type code into a comment box, so I've posted this answer separately.If you want to process an handler received during the call to
fgetc
that returnsEOF
, you should also checkinsert_an_A
after exiting the while loop.Note also that in general the best practice for signal handlers is to set a global variable and return from the handler. Elsewhere in your program, look for that variable changing and react appropriately.