通过POSIX使用串行端口时,建议先使用tcgetattr()
保存原始属性,然后再使用tcsetattr()
进行更改,然后在关闭端口之前将其还原。通过按Control-C终止程序或当程序收到SIGINT
时该怎么办?我没有在任何系列教程中都看到过这一点。
显然,atexit()
函数是不够的,因为默认的SIGINT
处理程序不会调用它。因此,似乎必须安装信号处理程序,才能将属性恢复到仍然打开的任何串行端口。从信号处理程序调用tcsetattr()
甚至安全吗?
可以简单地认为这个问题无关紧要,但是使用Control-C终止程序是很常见的,尤其是可能花费数十秒才能完成操作的程序。如果在这种情况下不保留串行端口设置是可以的,那么似乎根本没有理由保留它们。如果有的话,最好不要打扰,也不要前后矛盾。
我发现了一些examples of source code doing the above,但是没有充分的文献记载。我想我对这是否是一个好主意的讨论感兴趣。谢谢。
最佳答案
经过进一步的研究,我认为我已经对此表示满意。
首先,在man page for signal中,我注意到特别允许信号处理程序与其他一些信号处理程序一起调用tcsetattr()
:
信号处理程序例程必须非常小心,因为在其他任意位置中断了其他地方的处理。 POSIX具有“安全功能”的概念。如果信号中断了一个不安全的函数,并且处理程序调用了一个不安全的函数,则该行为是不确定的。在各种标准中明确列出了安全功能。 POSIX.1-2003列表是...`raise()`... signal()`... tcsetattr()`[已剪裁为相关的]
这强烈表明POSIX委员会已经牢记了这种确切的想法,并导致了一种直接的方法:打开序列并保存其属性后,您就更改SIGINT
处理程序,然后在处理程序中还原它们并旧的SIGINT
处理程序,然后重新引发信号:
static void (*prev_sigint)( int );
static termios saved_attr;
static int fd;
static void cleanup( int ignored )
{
tcsetattr( fd, TCSANOW, &saved_attr );
signal( SIGINT, prev_sigint );
raise( SIGINT );
}
int main( void )
{
open_serial_and_save_attrs();
prev_sigint = signal( SIGINT, cleanup );
...
}
关于serial-port - 在Control-C之后还恢复串行端口属性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4009411/