我有一个程序,该程序可以创建许多线程并运行,直到关闭嵌入式计算机的电源,或者用户使用kill
或ctrl``c
终止该过程为止。
这是一些代码以及main()的外观。
static int terminate = 0; // does this need to be volatile?
static void sighandler(int signum) { terminate = 1; }
int main() {
signal(SIGINT, sighandler);
// ...
// create objects, spawn threads + allocate dynamic memory
// ...
while (!terminate) sleep(2);
// ...
// clean up memory, close threads, etc.
// ...
signal(SIGINT, SIG_DFL); // is this necessary?
}
我想知道几件事:
是否需要信号处理?
我在这个线程中读到“ Linux
C为正常终止捕获了终止信号”
,显然,操作系统将为我处理清理工作。因此,我可以仅用无限循环替换信号处理程序,然后让OS正常退出线程,取消分配内存等吗?
关于干净终止,还有其他需要关注的信号吗?该线程“ SIGINT与其他终止信号有何关系?” ,对于列出我可能关心的所有信号很有用,但是实际上需要处理多少个信号?
在我的示例中,terminate变量是否必须是volatile?我看过很多例子,其中该变量是易失性的,而另一些则不是。
我读过,signal()
现在已弃用,请使用sigaction()
。有没有真正好的例子来说明如何从上一个signal()
通话转换?我在必须创建/通过的新结构以及它们如何组合在一起方面遇到了麻烦。
第二个电话signal()
需要吗?
是否有类似的事情需要我关注sigaction()
?
明确地说,我要做的就是让我的:main循环运行,直到其中一个ctrl``c
断开或电源断开或发生真正的不良情况。
[Q-3]
terminate
我的示例中的变量是否必须为volatile
?我看过很多例子,其中该变量是易失性的,而另一些则不是。
标志terminate
应为volatile sig_atomic_t
:
因为处理函数可以异步调用。也就是说,处理程序可能在程序中的任何地方被意外地调用。如果两个信号在很短的间隔内到达,则一个处理程序可以在另一个处理程序中运行。最好声明为volatile sig_atomic_t
,始终以原子方式访问此类型,以避免不确定是否中断对变量的访问。volatile
告诉编译器不要进行优化并将其放入寄存器。(有关详细信息,请阅读:原子数据访问和信号处理)。另
一种参考:24.4.7原子数据访问和信号处理。此外,7.14.1.1-5中的C11标准指示只能volatile sig_atomic_t
从信号处理程序访问对象的(访问其他对象具有未定义的行为)。
[Q-4]
我已经阅读了signal()
现在已弃用的,并使用sigaction()
。有没有真正好的例子来说明如何从上一个signal()
通话转换?我在必须创建/通过的新结构以及它们如何组合在一起方面遇到了麻烦。
以下示例(以及注释中的链接)可能会有所帮助:
// 1. Prepare struct
struct sigaction sa;
sa.sa_handler = sighandler;
// 2. To restart functions if interrupted by handler (as handlers called asynchronously)
sa.sa_flags = SA_RESTART;
// 3. Set zero
sigemptyset(&sa.sa_mask);
/* 3b.
// uncomment if you wants to block
// some signals while one is executing.
sigaddset( &sa.sa_mask, SIGINT );
*/
// 4. Register signals
sigaction( SIGINT, &sa, NULL );
参考资料:
sigaction()
“第11章:进程和信号”中很好地解释了您的代码。 [Q-5] 是否需要再次致电
signal()
?是否有类似的事情需要我关注sigaction()
?
我不清楚为什么在程序终止之前将其设置为默认操作。我认为以下段落将为您提供答案:
处理信号
信号调用仅对 一个 信号出现建立信号处理。在调用信号处理函数之前, 库会重置信号,以便在再次出现相同信号时执行默认操作
。重置信号处理有助于防止无限循环,例如,如果在信号处理程序中执行的操作再次引发相同的信号。如果希望您的处理程序每次出现时都用于信号,则必须在处理程序中调用signal来恢复它。您应谨慎恢复信号处理。例如,如果您继续恢复SIGINT
处理,则可能会失去中断和终止程序的能力。
该signal()
函数仅定义下一个接收到的信号的处理程序, 之后将恢复默认处理程序 。因此, 如果程序需要使用非默认处理程序继续处理信号
,则有必要调用信号处理signal()
程序。
阅读讨论以获取更多参考:何时重新启用信号处理程序。
[Q-1a] 是否需要信号处理?
是的,Linux将为您进行清理。例如,如果您不关闭文件或套接字,则Linux将在进程终止后进行清理。但是Linux可能没有必要立即执行清理,并且可能需要一些时间(可能是为了保持较高的系统性能或其他一些问题)。例如,如果您不关闭tcp-
socket并且程序终止,则内核将不会立即关闭套接字以确保所有数据都已传输,TCP尽可能保证传送。
[Q-1b] 因此,我可以仅用无限循环替换信号处理程序,然后让OS正常退出线程,取消分配内存等吗?
不,操作系统仅在程序终止后才执行清理操作。进程执行时,分配给该进程的资源不会被OS占用。(操作系统无法知道您的进程是否处于无限循环中-这是无法解决的问题)。如果您希望进程终止后,操作系统为您执行清理操作,那么您就不需要处理信号(即使您的进程被信号异常终止)。
[Q] 我要完成的所有工作都是为了使我的:main循环运行,直到
ctrl``c
或断开电源或发生真正的不良情况。
不,有限制!您无法捕获所有信号。某些信号是不可捕获的,例如SIGKILL
并且SIGSTOP
都是终止信号。引用一:
[—宏:int
SIGKILL
](http://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html)
该
SIGKILL
信号用于导致程序立即终止。它 不能被处理或忽略,因此总是致命的。 它也 没有 能够阻止这个信号。
我不确定,但也许您可以在Windows系统中执行以下操作:通过编写TSR(某种内核模式挂钩)。我从论文撰写时就记得某些病毒甚至无法从任务管理器中终止,但我也相信它们会通过管理员权限欺骗用户。
希望这个答案对您有帮助。
在Linux中,当一个程序(可能有多个线程)收到信号(如SIGTERM或SIGHUP)时会发生什么? 哪个线程拦截信号?多个线程可以获得相同的信号吗?是否有专门处理信号的特殊线程?如果没有,那么处理信号的线程内部会发生什么?信号处理程序例程完成后,执行如何继续?
问题内容: 谁能分享使用信号量的简单示例?如果可能的话,可以在没有信号量的情况下解决任务,然后再通过信号量来了解任务的主要思想。 问题答案: 这是一个简单的信号量实现: 该方法发送一个信号,该信号内部存储在信号量中。该方法等待信号。接收到信号标志后,再次将其清除,然后退出该方法。 阅读本文并看一下这个例子
阻塞信号是保持该信号并推迟发送,直到阻塞解除,但不会丢失。 结构体sigset_t(信号集合) 其中每一位对应系统支持的一种信号。结构体内部是数组。 函数 函数名 描述 [[sigemptyset sigempty]] 初始化信号集为空集 [[sigfillset sigfillset]] 初始化信号集包含全部信号 [[sigaddset sigaddset]] 向信号集中添加信号 [[sigde
Linux常用31个信号(1~31)。signal.h中有个常量NSIG定义了信号的个数,其值通常为为64。 编号 信号 编号 信号 编号 信号 1 SIGHUP 2 SIGINT 3 SIGQUIT 4 SIGILL 5 SIGTRAP 6 SIGABRT 7 SIGBUS 8 SIGFPE 9 SIGKILL 10 SIGUSR1 11 SIGSEGV 12 SIGUSR2 13 SIGPIP
问题内容: 在Linux中,当程序(可能具有多个线程)接收到诸如SIGTERM或SIGHUP之类的信号时会发生什么? 哪个线程拦截信号?多个线程可以得到相同的信号吗?有专门用于处理信号的特殊线程吗?如果不是,那么在处理信号的线程内部会发生什么?信号处理程序例程完成后,如何恢复执行? 问题答案: 根据您所使用的Linux内核版本,这会有些许细微差别。 假设有2.6个posix线程,并且如果您正在谈论
问题内容: 我正在尝试从Flickr中读取RSS提要,但它具有一些不能被Simple XML读取的节点(,等等)。 我该如何解决?当我查看DOM文档时,我的头很痛。所以我想避免这种情况,因为我不想学习。 我正在尝试获取缩略图。 问题答案: 解决方案在这篇不错的文章中进行了解释。您需要用于访问包含名称空间的XML元素的方法。此代码段摘自该文章: