简单的Linux的信号处理 [英] Simple Linux Signal Handling

查看:111
本文介绍了简单的Linux的信号处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个创建多个线程和运行,直至电源关断的嵌入式计算机,或用户使用或<大骨节病> CTRL 程序<大骨节病> C 终止进程。

下面是一些code和如何在main()的样子。

 静态INT终止= 0; //这是否需要挥发?静态无效sighandler(INT正负号){终止= 1; }诠释主(){
  信号(SIGINT,sighandler);
  // ...
  //创建对象,生成线程+动态分配内存
  // ...
  而睡眠(2)(终止!);
  // ...
  //清理内存,关闭线程,等等。
  // ...
  信号(SIGINT,SIG_DFL); //这个必要吗?
}

我想知道的几件事情:


  1. 正在处理任何必要的信号?​​结果
    我在这个线程读取<一个href=\"http://stackoverflow.com/questions/7376228/linux-c-catching-kill-signal-for-graceful-termination\">\"Linux ç醒目杀信号正常终止,,显然操作系统将处理清理我。
    因此,我能只用一个无限循环替换信号处理程序,并让OS正常退出线程,去分配内存,等等?


  2. 有没有我需要关心的是关于终止干净任何其他信号?此线程<一个href=\"http://stackoverflow.com/questions/4042201/how-does-sigint-relate-to-the-other-termination-signals\">\"How不SIGINT涉及到其他的终止信号?,是列出所有我可以与相关的信号是有用的,但究竟有多少实际需要处理?


  3. 在是否我的例子中终止变量必须波动?我见过很多例子,这个变量是挥发性的,其他地方是没有的。


  4. 我读过信号()现在是很precated,并使用的sigaction()。是否有任何真正的好例子,说明如何从previous 信号转换()打电话?我在与新的结构,我要制造事端/通行证,这一切是如何结合在一起。


  5. 第二呼叫信号()有必要吗?结果
    是否有类似的,我需要去关注的的sigaction()的东西


需要明确的是,所有我试图完成对有我:主循环运行,直到<大骨节病> CTRL <大骨节病> C 或电源断开或东西真的不好的事情发生。


解决方案

  

[Q-3] 有没有在我的例子终止变量必须是挥发性?我有
  看过很多例子,这个变量是挥发性的,和其他人在哪里
  事实并非如此。


标志终止挥发性sig_atomic_t

由于处理功能可以异步调用。即,一个处理程序可能在程序中,取消predictably任何点被调用。如果在很短的时间间隔内两个信号到达,一个处理程序可以在另一运行。它被认为是更好的做法,声明挥发性sig_atomic_t ,这种类型总是原子访问,避免对中断给一个变量的访问不确定性。 挥发性告诉编译器不优化,放入寄存器。 (阅读:原子数据访问和信号处理的详细赎罪)。结果
还有一个参考:<一href=\"http://www.gnu.org/software/libc/manual/html_node/Atomic-Data-Access.html#Atomic-Data-Access\">24.4.7原子数据访问和信号处理。
此外,在7.14.1.1-5的C11标准表示仅挥发性sig_atomic_t对象可以从信号处理(访问别人是未定义行为)进行访问。


  

[Q-4] 我读过信号()现在去precated,并使用的sigaction()。是
  有没有真正的好例子,说明如何从转换
  previous 信号()打电话?我在与新结构麻烦
  我要创建/通行证,这一切是如何结合在一起。


下面的例子(与评价的链接)可以是有帮助的:

  // 1 prepare结构
结构sigaction的SA;
sa.sa_handler = sighandler;// 2.如果处理中断(如处理异步调用)重启功能
sa.sa_flags = SA_RESTART;// 3.设定为零
sigemptyset(安培; sa.sa_mask);/ * 3B。
 //如果你想阻止取消注释
 而正在执行一个//一些信号。
sigaddset(安培; sa.sa_mask,SIGINT);
* /// 4.注册信号
的sigaction(SIGINT,和放大器; SA,NULL);

引用:


  1. 开始Linux的编程,第4版:在这本书中,你究竟code与解释的sigaction()在很好第11章:进程和信号。

  2. 的sigaction文档,其中包括一个示例(快学习)。

  3. GNU C库:信号处理结果
    <子> *我从 1 ,$开始p $ psently我读 3 GNU库


  

[Q-5] 是第二次调用信号()有必要吗?是否有类似的东西,我需要去关注的的sigaction()


为什么你将它设置为默认行动前程序终止我不清楚。我想下面的段落会给你一个答案:


  

处理信号


  
  

到信号的呼叫建立信号处理只有一个的信号的发生。信号处理函数被调用之前,的库中,以便进行默认操作,如果再次发生相同的信号复位信号。复位信号处理有助于prevent无限循环,如果,例如,在信号处理程序中执行的动作再次将相同的信号。如果你想被用于每次发生时的信号处理程序,您必须在处理程序中调用信号恢复它。你应该在复原的信号处理谨慎。例如,如果你不断地恢复 SIGINT 处理,你可能会失去中断和终止程序的能力。


信号()函数定义了默认的处理程序恢复而已,的之后,下一个接收信号的处理程序的。因此,有必要对信号处理程序来调用信号()如果程序需要继续使用非默认的处理程序处理的信号。

阅读进一步参考讨论:<一href=\"http://cboard.cprogramming.com/linux-programming/150239-when-re-enable-signal-handlers.html\">When到重新启用信号处理程序。


  

[Q-1A] 是一种信号处理有必要吗?


是,Linux会为你做清理工作。例如,如果您不关闭文件或插座,Linux将进程终止后,应进行清理。但Linux的可不必立即执行清理,它可能需要一些时间(可能是保持系统性能高,或其他一些问题)。例如,如果你不关闭TCP套接字和程序终止内核将不会立即关闭套接字,以确保所有数据发送,如果可能的话TCP保证交付。


  

[Q-1B] 所以,我能只用一个无限循环替换信号处理程序,并让OS正常退出线程,去分配内存,等等?


没有,操作系统执行做清理程序结束之后。虽然进程执行,被分配给该进程的资源没有得到由OS声称。 (操作系统无法知道你的进程是否是一个无限循环或不 - 这是一个无法解决的问题)。如果您希望进程终止后,OS为您执行清理操作,那么你并不需要处理信号(即使在情况下,你进程异常信号终止)。


  

[Q] 所有我试图完成对有我:主循环运行,直到<大骨节病> CTRL <大骨节病> C 或电源断开或东西真的不好的事情发生。


没有,是有限制!你不能赶上所有信号。有些信号是不是开捕例如 SIGKILL SIGSTOP 无一不是终止信号。引用之一:


  

- 宏:int SIGKILL


  
  

SIGKILL 信号用于立即引起程序终止。它的无法处理或忽略,因此总是致命的。不可以可以阻止这个信号。


所以,你不能让不能被中断的程序(不间断程序)

<子>
我不知道,但可能是你可以做这样的事情在Windows系统:通过写的TSR(某种内核模式挂钩的)。我从我的论文的时间记住,有些病毒无法甚至从任务管理器终止,但我也相信,他们通过管理员权限用户欺骗。结果

我希望这回答会帮助你。

I have a program that creates many threads and runs until either power is shutdown to the embedded computer, or the user uses kill or ctrlc to terminate the process.

Here's some code and how the main() looks.

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?
}

I'm wondering a few things:

  1. Is any signal handling necessary?
    I read in this thread
    "Linux C catching kill signal for graceful termination", that apparently the OS will handle cleanup for me. Therefore, can I just replace the signal handler with just an infinite loop and let the OS gracefully exit the threads, de-allocate the memory, etc?

  2. Are there any other signals that I need to be concerned with regarding clean termination? This thread "How does SIGINT relate to the other termination signals?", was useful to list all the signals I may be concerned with, but how many actually required handling?

  3. Does the terminate variable in my example have to be volatile? I've seen many examples where this variable is volatile, and others where it is not.

  4. I've read that signal() is now deprecated, and to use sigaction(). Are there any really good examples to show how to convert from the previous signal() call? I'm having trouble with the new structure that I have to create/pass and how it all fits together.

  5. Is the second call to signal() necessary?
    Is there something similar that I need to be concerned with for sigaction()?

To be clear, all I'm trying to accomplish to to have my: main loop run until either ctrlc or power is disconnected or something really bad happens.

解决方案

[Q-3] Does the terminate variable in my example have to be volatile? I've seen many examples where this variable is volatile, and others where it is not.

The flag terminate should be volatile sig_atomic_t:

Because handler functions can be called asynchronously. That is, a handler might be called at any point in the program, unpredictably. If two signals arrive during a very short interval, one handler can run within another. And it is considered better practice to declare volatile sig_atomic_t, this type are always accessed atomically, avoid uncertainty about interrupting access to a variable. volatile tells the compiler not to optimize and put it into register. (read: Atomic Data Access and Signal Handling for detail expiation).
One more reference: 24.4.7 Atomic Data Access and Signal Handling. Furthermore, the C11 standard in 7.14.1.1-5 indicates that only objects of volatile sig_atomic_t can be accessed from a signal handler (accessing others has undefined behavior).

[Q-4] I've read that signal() is now deprecated, and to use sigaction(). Are there any really good examples to show how to convert from the previous signal() call? I'm having trouble with the new structure that I have to create/pass and how it all fits together.

The example below (and the link in the comments) can be helpful:

// 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 );

references:

  1. Beginning Linux Programming, 4th Edition: in this book, exactly your code is explained with sigaction() nicely in "Chapter 11: Processes and Signals".
  2. The sigaction documentation, including an example (quick learning).
  3. The GNU C Library: Signal Handling
    *I started from 1, Presently I am reading 3 GNU-library

[Q-5] Is the second call to signal() necessary? Is there something similar that I need to be concerned with for sigaction()?

Why you set it to default-action before program termination is unclear to me. I think the following paragraph will give you an answer:

Handling Signals

The call to signal establishes signal handling for only one occurrence of a signal. Before the signal-handling function is called, the library resets the signal so that the default action is performed if the same signal occurs again. Resetting signal handling helps to prevent an infinite loop if, for example, an action performed in the signal handler raises the same signal again. If you want your handler to be used for a signal each time it occurs, you must call signal within the handler to reinstate it. You should be cautious in reinstating signal handling. For example, if you continually reinstate SIGINT handling, you may lose the ability to interrupt and terminate your program.

The signal() function defines the handler of the next received signal only, after which the default handler is reinstated. So it is necessary for the signal handler to call signal() if the program needs to continue handling signals using a non-default handler.

Read a discussion for further reference: When to re-enable signal handlers.

[Q-1a] Is any signal handling necessary?

Yes, Linux will do cleanup for you. For example if you don't close a file or a socket, Linux will do the cleanup after the process terminates. But Linux may not necessary perform the clean up immediately and it may take some time (may be to keep system performance high or some other issues). For example if you don't close a tcp-socket and the program terminates the kernel will not close the socket immediately to ensure all data has been transmitted, TCP guarantees delivery if possible.

[Q-1b] Therefore, can I just replace the signal handler with just an infinite loop and let the OS gracefully exit the threads, de-allocate the memory, etc?

No, operating system performs do clean-up only after program terminates. While a process executes, resources that are allocated to that process don't get claimed by the OS. (The OS can't know whether your process is in an infinite loop or not - this is an unsolvable problem). If you want that after process termination the OS performs the clean-up operations for you, then you don't need to handle signals (even in case your process abnormally terminated by a signal).

[Q] All I'm trying to accomplish to to have my: main loop run until either ctrlc or power is disconnected or something really bad happens.

No, there is a limitation! You can't catch all signals. Some signals are not catchable e.g. SIGKILL and SIGSTOP and both are termination signals. Quoting one:

— Macro: int SIGKILL

The SIGKILL signal is used to cause immediate program termination. It cannot be handled or ignored, and is therefore always fatal. It is also not possible to block this signal.

So you can't make a program that cannot be interrupted (an uninterrupted program)!

I am not sure but may be you can do something like this in Windows systems: by writing TSRs (some sort of kernel-mode hooking). I remember from my thesis time that some viruses couldn't be terminated even from task manager but I also believe that they trick user by admin permissions.

I hope this answer will help you.

这篇关于简单的Linux的信号处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆