问题描述
我发现在互联网低于code,我想了解Linux的定时器工作,反正你可以看到下面的C1的是全局变量,如果同时正在研究它,会发生什么计时器熄灭,改变了C1的价值,我需要在那里的锁?
// timertst1.c:简单的定时器演示程序。使用跨海湾合作委员会
//弗斯。 1.00 - 21.Oct。 2002年
// [email protected]#包括LT&;&stdio.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&signal.h中GT;
#包括LT&; SYS / time.h中>//这是一个定时器处理程序。
INT计数器1 = 0;
无效timerHandler(INT正负号)
{
的printf(timerHandler:计数器=%d个\\ N,计数器1 ++);
fflush(标准输出);
}//这是唯一的主要功能。INT主要(无效)
{
结构sigaction的SA;
结构体itimerval定时器; //安装定时器处理程序... memset的(安培; SA,0,sizeof的(SA));
sa.sa_handler =安培; timerHandler;
的sigaction(SIGALRM,&安培; SA,NULL); //配置定时器每100毫秒到期... timer.it_value.tv_sec = 0; //首先超时
timer.it_value.tv_usec = 500000;
timer.it_interval.tv_sec = 0; //间隔
timer.it_interval.tv_usec = 500000; //开始计时器... setitimer函数(ITIMER_REAL,&安培;定时器,NULL); setitimer函数(ITIMER_REAL,&安培;定时器,NULL);
//不要提... 而(1){
的printf(我在这里等待interuppted =%d个\\ N,C1的);
//一些工作;
计数器1 ++;
//一些其他的工作;
}
}
信号处理是很危险的。操作系统是要打断你的程序,不管它在做什么,并运行处理程序;当处理程序返回,操作系统将你的程序返回到它在做什么。
让我们说, C1的++
被编译到负载,增量和存储。如果负载和存储之间的中断火灾,则指令序列将是负载,负载,增量,递增,商店,商店。变量就上去了又一个,不是两个;灾害!你说的没错,这看起来像一个典型的多线程问题。
如果我们增加一个锁,会发生什么?现在不是负担,增量,商店,我们得到锁定,加载,增量,存储,解锁。但是,如果我们锁定和解锁之间,而在信号触发时,OS跳到我们对进入处理程序 - 它不会首先让我们code解锁。当处理程序试图锁定,主()仍然持有锁,所以我们死锁。灾难!
在安全的事情就是写你的信号处理程序,以便它只是让记下哪些必须做,写code采取的实际上做在别处照顾。但是,即使不一定是简单的 - 如果你的信号处理程序本身中断什么?在这种特殊情况下不是问题,但值得考虑的兔子洞有多深的例子。编写正确的信号处理是很难的。有一些技巧,比如你可以阻断信号处理。但它仍然很难。
I found the below code in the Internet, I'm trying to understand how Linux timer works, anyway, as you can see below the counter1 is global var, what will happen if the while is working on it and the timer goes off and changed the value of counter1, do I need a lock in there?
// timertst1.c: Simple timer demo program. Use cross-gcc
// Vers. 1.00 - 21.Oct. 2002
// [email protected]
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
// This is a timer handler.
int counter1 = 0;
void timerHandler (int signum)
{
printf ("timerHandler: counter= %d\n", counter1++);
fflush (stdout);
}
// This is the one and only main function.
int main (void)
{
struct sigaction sa;
struct itimerval timer;
// Install the timer handler...
memset (&sa, 0, sizeof (sa));
sa.sa_handler= &timerHandler;
sigaction (SIGALRM, &sa, NULL);
// Configure the timer to expire every 100 msec...
timer.it_value.tv_sec= 0; // First timeout
timer.it_value.tv_usec= 500000;
timer.it_interval.tv_sec= 0; // Interval
timer.it_interval.tv_usec= 500000;
// Start timer...
setitimer (ITIMER_REAL, &timer, NULL); setitimer (ITIMER_REAL, &timer, NULL);
// Do noting...
while (1) {
printf("i'm here waiting to be interuppted = %d\n",counter1);
//some work;
counter1++;
//some other work;
}
}
Signal handlers are dangerous. The OS is going to interrupt your program, whatever it was doing, and run the handler; when the handler returns, the OS will take your program back to what it was doing.
Let's say that counter1++
is compiled to a load, an increment and a store. If the interrupt fires between the load and the store, then the sequence of instructions will be load, load, increment, increment, store, store. The variable will go up by one, not two; disaster! And you're right, this looks like a classic multi-threading issue.
What happens if we add a lock? Now instead of load, increment, store, we get lock, load, increment, store, unlock. But if the signal fires while we're between lock and unlock, the OS jumps us right into the handler - it doesn't let our code unlock first. When the handler tries to lock, main() is still holding the lock, so we deadlock. Disaster!
The safe thing to do is to write your signal handler so it just makes a note of what has to be done, and write code to take care of actually doing that elsewhere. But even that is not necessarily simple - what if your signal handler is itself interrupted? Not a problem in this particular case, but worth considering an example of how deep the rabbit hole goes. Writing correct signal handlers is hard. There are some tricks, for instance you can block signal handlers. But it's still hard.
这篇关于对全局变量的Linux定时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!