即使运行它们的进程很忙,signal()和alarm()也能工作吗?或者我应该在另一个专用进程上运行它?
我目前正在实施一个生产者/消费者问题计划。我有一个父进程和几个子进程。一切正常,但现在我需要让我的程序每 k
毫秒输出我的程序正在执行的任务的进度。
起初我认为也许只是使用 signal()
和 alarm()
函数,但从一些初步测试来看,我一直在做这件事。似乎还不够。我查看了几个日志文件,似乎 onAlarm()
没有被调用。我想这与父母和孩子都“忙”而没有收到事件有关?或者即使他们很忙,他们也应该能够在 onAlarm() 上接收呼叫?我看到的唯一解决方法是创建另一个流程,该流程具有单一责任来处理此问题。
这是我的“事件”代码:
void onAlarm() {
signal(SIGALRM, onAlarm);
alarm(0.01);
fprintf(outputFile, "ALAAAAAAAAAAAAAARMMMMMMMMMMM: %d\n", numberOfBytesRead);
}
int main() {
signal(SIGALRM, onAlarm);
alarm(0.01);
...
}
I am currently implementing a Producer/Consumers problem program. I have one parent and several child processes. Everything is working but now I need to make my program output each k
milliseconds the progress of the task my program is doing.
At first I thought that maybe it'd be just about using the signal()
and alarm()
functions, but from some preliminary testing I've been making it doesn't seem enough. I have watched over several log files and it seems onAlarm()
is not being called. I guess it has to do with the fact that as that both parent and children are "busy" they don't receive the events? Or even if they are busy, they should be able to receive calls on onAlarm()? The only workaround I see for this is to create yet another process, that has as single responsability dealing with this.
This is my "events" code:
void onAlarm() {
signal(SIGALRM, onAlarm);
alarm(0.01);
fprintf(outputFile, "ALAAAAAAAAAAAAAARMMMMMMMMMMM: %d\n", numberOfBytesRead);
}
int main() {
signal(SIGALRM, onAlarm);
alarm(0.01);
...
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您的主要问题是
alarm()
需要整数秒 - 并且alarm(0)
用于取消任何未完成的警报。自然的后续问题是:
我不确定批准的方式是什么。在某些系统上,有一个微睡眠 (
usleep()
) 调用,但这不是 POSIX 2008 的一部分。 POSIX 中的usleep()
的直接类似物出现为nanosleep()
。有一个
sigtimewait()
可以大概可以用来达到这样的效果。 (您也许可以使用setitimer()
和getitimer()
代替usleep()
。)所有这些的困难在于你要么是同步的(你不能在工作的同时继续工作)等待信号到达)或未发送信号。我没有立即看到 POSIX 亚秒级警报机制,该机制允许您在等待超时时继续工作。
Your main problem is that
alarm()
takes an integer number of seconds - andalarm(0)
is used to cancel any outstanding alarms.The natural follow-up question is:
I'm not sure what the approved way is. On some systems, there is a micro-sleep (
usleep()
) call, but that is not part of POSIX 2008. The direct analogue ofusleep()
in POSIX appears to benanosleep()
.There is a
sigtimewait()
which could probably be used to achieve the effect. (You might be able to usesetitimer()
andgetitimer()
in lieu ofusleep()
.)The difficulty with all of these is that you are either synchronous (you can't get on with work while waiting for a signal to arrive) or not sent a signal. I don't immediately see a POSIX sub-second alarm mechanism, which would allow you to continue work while waiting for the timeout.
我不确定这是否是您的问题,但在信号处理程序中使用
fprintf
并不安全。例如,信号可能在 fprintf 本身内部引发,这可能会导致意外行为。或者,fprintf
可能正在分配一些内存,并且在malloc
运行时捕获了信号。这种事情会产生看似随机的死锁和剧烈的崩溃。在信号处理程序内进行复杂计算的安全方法是让信号处理程序更改已运行的事件循环的状态,或类似的操作。或者,对于您的具体问题,正如其他人建议的那样,避免使用信号并使用更直接的睡眠呼叫。
I'm not sure whether or not this is your problem, but it's not safe to
fprintf
inside a signal handler. For example, the signal could be raised inside offprintf
itself, which might lead to unexpected behavior. Or perhapsfprintf
is allocating some memory, and the signal was caught whilemalloc
was running. This kind of thing can produce seemingly random deadlocks and violent crashes.The safe way to do complex computations inside a signal handler is for your signal handler to alter the state of an already-running event loop, or something like this. Or, for your specific problem, as others suggest, avoid using signals for this and use a more straightforward sleep call.
对你的问题的简短回答是肯定的。即使它们附加的进程正忙于进行计算或某种类型的 io/等待,它们仍然可以工作。唯一的限制是该进程不会更改并使用
SIGALRM
本身,这会导致问题。当信号到达时,进程/线程的正常执行被挂起并调用信号处理程序。这就是信号处理的整体思想以及它被称为异步的原因。你的问题的较长答案是否定的。您不想通过信号处理程序机制实现进度报告,因为您可以在信号处理程序中使用的 API 非常有限。确切地说,您提到的示例是错误的,因为它使用
fprintf(3)
。正如其中一个答复信号中所述,信号是异步的。这意味着,如果信号到达调用malloc(3)
的主代码中间,并且您的代码也调用malloc(3)
(您永远无法要知道,printf(3)
可能会调用malloc(3)
来进行缓冲和其他需求),那么您将破坏 malloc 自己的内部数据结构并导致程序出错。您甚至可能在调用自己的非异步安全函数时遇到问题。您有一个可以在信号处理程序内部调用的安全函数列表,您可以在异步信号安全函数
下的man 7 signal
中找到这些函数。所以,是的,从技术上讲,只要您愿意使用这个简化的 API,您就可以通过alarm(3)
实现进度报告,这就是我不会这样做的原因,除非程序是单线程的设计,除非我真的没有办法看到进度报告代码受到未来增强的影响,这将使其很难在信号处理程序中编写。关于您的示例的另一个问题是
alarm(2)
不接受亚秒参数,上面的示例应该完全编译失败,或者至少显示一些有关该事实的警告。对于微秒分辨率,您可以将
setitimer(2)
与ITIMER_REAL
一起使用,如前所述。对于 Linux 上的纳秒分辨率,您可以使用
timer_create(2)
、CLOCK_REALTIME
、SIGEV_SIGNAL
和timer_settime(2)
还有更多功能。这是一些示例代码。请注意,这使用了我自己的错误处理宏。您可以在此项目中看到它处于可编译状态 演示Linux
The short answer to your question is yes. They work even though the process they attached to is busy doing calculations or io/waiting of some sort. The only limitation is that the process is not changing and playing with
SIGALRM
itself which would cause problems. When a signal arrives the normal execution of a process/thread is suspended and the signal handler is called. That is the whole idea of signal handling and why it is calledasynchronous
.The longer answer to your question is no. You wouldn't want to implement progress report via the signal handler mechanism since the API that you can use inside a signal handler is very limited. To be exact the example that you referred to wrong since it uses
fprintf(3)
. As has been stated in one of the replies signals are asynchronous. This means that if the signal arrives in the middle of the main code calling say,malloc(3)
, and your code callsmalloc(3)
as well (you can never know,printf(3)
may callmalloc(3)
for buffering and other needs) then you will corrupts mallocs own internal data structures and cause the program to fault. You may even have problems calling your own functions which are not async safe. You have a list of safe functions that you can call inside a signal handler and you can find those inman 7 signal
underAsync-signal-safe functions
. So yes, technically you can implement progress reporting viaalarm(3)
as long as you are willing to live with this reduced API and that is the reason I would not do it unless the program is single threaded by design and unless there is really no way in which I see the progress reporting code as being subject to future enhancements that will make it hard to write inside a signal handler.Another problem which has been stated about your example is that
alarm(2)
does not accept sub-second arguments and the example above should have failed compilation completely or at least showed some warnings about that fact.For microsecond resolution you can use
setitimer(2)
withITIMER_REAL
as has been stated.For nanosecond resolution on Linux you can use
timer_create(2)
,CLOCK_REALTIME
,SIGEV_SIGNAL
andtimer_settime(2)
that have many more features.Here is some example code. Note that this uses my own error handling macros. You can see it in a compilable state in this project demos-linux
如果您需要计时器的亚秒级分辨率,您可以使用第二个 posix 线程和
usleep
If you need sub-second resolution on a timer, you can use a second posix thread and a
usleep
对于发送信号的亚秒定时器,您需要使用 POSIX setitimer(2) 函数。
For a sub-second timer sending a signal, you need to use the POSIX setitimer(2) function.