how to implement timer's callback function in C under Linux
I have searched the possible solution on many forums for several days but have no luck; ( I post my question here and your reply is greatly appreciated.
IDEA: Use a script to control lights (in C under Linux)
APPLICATION SCENARIO I have three lights: red, blue and green. The script has the schedules to control them. For example, From now in 10 seconds, turn on the red light for 2 seconds; From now in 15 seconds, turn on the blue light for 10 seconds; From now in 21 seconds, turn on the red light for 5 seconds; From now in 5 seconds, turn on the green light for 7 seconds; From now in 103 seconds, turn on the green light for 11 seconds; ….. When and how long to turn on the light are totally arbitrary. And this program should be able to expand to hundred lights and thousands s开发者_运维知识库chedules.
HOW TO CODE IT My idea is to have two processes and one mailbox : The first process reads the script file and parse the schedules into many timers. Once the timer expires, it send a message (including light ID and action – ON or OFF --) to the mailbox. The second process is to turn on or off the specified light based on the message from the mailbox.
Each schedule will be parsed into two timers: Schedule: From now in 10 seconds, turn on the red light for 2 seconds; Parsed to: Timer 1: timer will expire in 10 seconds; once expire, it passes the light ID (red light) and action (ON) as a message to the mailbox; Timer 2: timer will expire in (10+2) seconds; once expire, it passes the light ID (red light) and action (OFF) as a message to the mailbox;
The second process continually checks the mailbox and takes the proper action on proper light based on the received message.
MY QUESTION The timer in Linux () only issues the same SIGALRM signal once expired. It’s not possible for me to pass the light ID and action to the mailbox. Do I have any other way to do it? Thanks a lot.
SIGALRM isn't very reliable way to implement anything like this, you can't have more than one alarm request at the same time. And was that two process design meant to be something like at(1)/atd(8)? Unfortunately "at" isn't so precise to be used here, I'm not sure it even uses seconds when you schedule something.
However the problem is really simple to solve with just one program. Just split the task into events like "turn on/off light X", put them to ordered queue and have a loop that reads the queue and sleeps until it's time to act.
Tonttu's solution is pretty good.
Use a queue implemented with a linked list:
struct node {
struct node *next;
time_t t; // time to start
int action; // on / off
int lamp_id;
};
struct queue {
struct node *head;
struct node *tail;
};
Parse your file and fill the queue (keep it sorted by t). Next, your main loop should look like this:
time_t start = time(NULL);
while(!queue_empty()) {
time_t now = time(NULL) - start;
struct node *n = queue.head;
if(n->t <= now) {
lamp(n->lamp_id, n->action); // set the status of a lamp
queue_next();
} else {
sleep(n->t - now);
}
}
As usual, read the fine manual. You'll need time(2). If you need sub-second time, use gettimeodday(2).
精彩评论