Upon closely scouring through resources, I'm still not entirely sure how to write a proper and usable timer function in C. I am not working with threads (or parallelizable code). I simply want to write a stopwatch function that I can use to trigger a bit of code after a small amount of time has passed.
This is a very common use of a timer, in the situation of "time-out", where I have a client-server set up where the client is sending some data (UDP style with sendto(...) and recvfrom(...)). I have written my system so that the client sends a chunk of data in a packet struct I have defined, and the server processes it via CRC then sends back an acknowledgement packet (ACK) that the msg was received uncorrupted. However, I want to implement a time-out, where if the client does not receive an ACK in a certain period of time, the client resends the data chunk (of course the server is rigged to check for duplicates). I want to nest this bit of timer code in the client, and for some reason do not think this should be so difficult.
I have dug up old signal handling code from work I had done long ago, as this seems to be the only way I commonly see mentioned as a solution, can someone please guide me as to how I can use the following signal handling code to not just receive a timed signal but trigger an action of some sort. Conceptually, I feel it would be: "send data, start timer, after timer expires execute a resend, reset timer...repeat until that ACK received". Better yet, would be an easier way of writing a timer function, but it doesn't look like there's much hope for that given C is a low-level language....
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
extern char *strsignal(int sig);
void timer_handler(int a)
{
// handle signal
printf(">>>> signal caught\n");
printf(">>>> int parameter = %s\n", (char*) strsignal(a));
}
int main(int argc, char* argv[])
{
int retval;
struct itimerval timerValue;
struct itimerval oldTimerValue;
struct sigaction action;
action.sa_handler = &timer_handler;
action.sa_flags = SA_NODEFER;
// initialize timer parameters: expires in 5 seconds
timerValue.it_interval.tv_sec = 5;
timerValue.it_interval.tv_usec = 0;
timerValue.it_value.tv_sec = 5;
timerValue.it_value.tv_usec = 0;
// install signal handler to catch SIGALRM
//signal(SIGALRM, timer_handler);
sigaction(SIGALRM, &action, NULL);
retval = setitimer(ITIMER_REAL, &timerValue, &oldTimerValue);
if (-1 == retval)
perror("Could not set timer");
while(1);
return 0;
}
Xymostech provided the exact function I needed and after consulting the API for "select", which includes a small usage example, I modified the code there to fit what I needed and wrote a socket timer (for reads, those it's pretty simple to extend towards writes and such, as "select" has parameters for enabling this kind of check). Make sure you've included the following libraries as specified by the "select" API:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <stdio.h>
The following is the waittoread(...) function I created from the API example and works pretty well. This works well in the domain of my specific problem, however, if one is looking for a more generalized timer (i.e. not just for timing socket read and writes, or file descriptors) please consult signal handling (somewhat in the spirit of the code I posted in my initial question).
#define S1READY 0x01 // necessary for the function's bitwise OR operation
int waittoread(int s1, int timeout_value){
fd_set fds; // create set of sockets to be waited on
struct timeval timeout; // the time-out value
int rc; // # of sockets that are ready before timer expires
int result;
/* Set time limit. */
timeout.tv_sec = timeout_value;
timeout.tv_usec = 0;
/* Create a descriptor set containing the socket. */
FD_ZERO(&fds); // MACRO to reset the socket storage set so new ones can be added
FD_SET(s1, &fds); // add the socket descriptor into the socket set to wait on
rc = select(sizeof(fds)*4, &fds, NULL, NULL, &timeout); // build the socket-wait system
// another way of calling select that would be a better approach:
// rc = select(s1 + 1), &fds, NULL, NULL, &timeout);
if (rc==-1) {
perror("Error: Call to select failed.");
return -1;
}
result = 0;
if (rc > 0){
if (FD_ISSET(s1, &fds)) result |= S1READY; // if the result is non-zero, perform a BIT-wise OR to extract the true socket count #
}
return result;
}
Related
Registering a level triggered eventfd on epoll_ctl only fires once, when not decrementing the eventfd counter. To summarize the problem, I have observed that the epoll flags (EPOLLET, EPOLLONESHOT or None for level triggered behaviour) behave similar. Or in other words: Does not have an effect.
Could you confirm this bug?
I have an application with multiple threads. Each thread waits for new events with epoll_wait with the same epollfd. If you want to terminate the application gracefully, all threads have to be woken up. My thought was that you use the eventfd counter (EFD_SEMAPHORE|EFD_NONBLOCK) for this (with level triggered epoll behavior) to wake up all together. (Regardless of the thundering herd problem for a small number of filedescriptors.)
E.g. for 4 threads you write 4 to the eventfd. I was expecting epoll_wait returns immediately and again and again until the counter is decremented (read) 4 times. epoll_wait only returns once for every write.
Yep, I read all related manuals carefully ;)
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
static int event_fd = -1;
static int epoll_fd = -1;
void *thread(void *arg)
{
(void) arg;
for(;;) {
struct epoll_event event;
epoll_wait(epoll_fd, &event, 1, -1);
/* handle events */
if(event.data.fd == event_fd && event.events & EPOLLIN) {
uint64_t val = 0;
eventfd_read(event_fd, &val);
break;
}
}
return NULL;
}
int main(void)
{
epoll_fd = epoll_create1(0);
event_fd = eventfd(0, EFD_SEMAPHORE| EFD_NONBLOCK);
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = event_fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event_fd, &event);
enum { THREADS = 4 };
pthread_t thrd[THREADS];
for (int i = 0; i < THREADS; i++)
pthread_create(&thrd[i], NULL, &thread, NULL);
/* let threads park internally (kernel does readiness check before sleeping) */
usleep(100000);
eventfd_write(event_fd, THREADS);
for (int i = 0; i < THREADS; i++)
pthread_join(thrd[i], NULL);
}
When you write to an eventfd, a function eventfd_signal is called. It contains the following line which does the wake up:
wake_up_locked_poll(&ctx->wqh, EPOLLIN);
With wake_up_locked_poll being a macro:
#define wake_up_locked_poll(x, m) \
__wake_up_locked_key((x), TASK_NORMAL, poll_to_key(m))
With __wake_up_locked_key being defined as:
void __wake_up_locked_key(struct wait_queue_head *wq_head, unsigned int mode, void *key)
{
__wake_up_common(wq_head, mode, 1, 0, key, NULL);
}
And finally, __wake_up_common is being declared as:
/*
* The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just
* wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve
* number) then we wake all the non-exclusive tasks and one exclusive task.
*
* There are circumstances in which we can try to wake a task which has already
* started to run but is not in state TASK_RUNNING. try_to_wake_up() returns
* zero in this (rare) case, and we handle it by continuing to scan the queue.
*/
static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
int nr_exclusive, int wake_flags, void *key,
wait_queue_entry_t *bookmark)
Note the nr_exclusive argument and you will see that writing to an eventfd wakes only one exclusive waiter.
What does exclusive mean? Reading epoll_ctl man page gives us some insight:
EPOLLEXCLUSIVE (since Linux 4.5):
Sets an exclusive wakeup mode for the epoll file descriptor that is being attached to the target file descriptor, fd. When a wakeup event occurs and multiple epoll file descriptors are attached to the same target file using EPOLLEXCLUSIVE, one or more of the epoll file descriptors will receive an event with epoll_wait(2).
You do not use EPOLLEXCLUSIVE when adding your event, but to wait with epoll_wait every thread has to put itself to a wait queue. Function do_epoll_wait performs the wait by calling ep_poll. By following the code you can see that it adds the current thread to a wait queue at line #1903:
__add_wait_queue_exclusive(&ep->wq, &wait);
Which is the explanation for what is going on - epoll waiters are exclusive, so only a single thread is woken up. This behavior has been introduced in v2.6.22-rc1 and the relevant change has been discussed here.
To me this looks like a bug in the eventfd_signal function: in semaphore mode it should perform a wake-up with nr_exclusive equal to the value written.
So your options are:
Create a separate epoll descriptor for each thread (might not work with your design - scaling problems)
Put a mutex around it (scaling problems)
Use poll, probably on both eventfd and epoll
Wake each thread separately by writing 1 with evenfd_write 4 times (probably the best you can do).
We have an assignment to create a game in C. We can't use any external headers, and it should run on console.
I thought it would be cool to have animations going on. We already have a walking character and everything (printing matrix, updating, clearing screen, reprinting...), but it would be nice to have things such as running water, for example. To do that, I'd need a way to keep the program running while waiting for an input. As it currently is, the animations would stop as the user is prompted for an input (and he'll constantly be asked for directions), so it wouldn't work.
I'm wondering if there'd be a way to keep the animation running while the input prompt is still going, maybe having a timeout for the input function and re-prompting every frame until the user starts typing. We're familiar with C, but not with any of the obscure functions and headers that could be used to work around this problem.
How can I keep the program running while waiting for input?
You can use the select to monitor a file or a group of file descriptors until they have input available. Depending on the structure of your program you could also use asynchronous input where a callback is called when I/O is signaled as ready for a given file descriptor.
The rough snippet below shows the necessary methodology to allow for the callback action_handler to be called when input becomes available on the target file description, which emittes SIGIO. This allows for the input to be processed when it arrives, if it arrives. Using a socket (lets assume UDP) you would have something similar to the following.
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
...
create and bind socket
...
/** Set sigaction to use sigaction callback and not handler */
act.sa_flags = SA_SIGINFO; // Enables sigaction instead of handler
act.sa_sigaction = action_handler; // Callback function
/** Set mask to ignore all signals except SIGIO during execution of handler */
sigfillset(&act.sa_mask); // Mask all
sigdelset(&act.sa_mask, SIGIO); // Clear SIGIO from mask
/** Set callback for SIGIO */
sigaction(SIGIO, &act, NULL)
/** Set socket io signals to async and make sure SIGIO is sent to current
* process when a TCP connection is made on the socket
* */
file_status = fcntl(socket_fd, F_GETFL); // Get current status
file_status |= O_ASYNC | O_NONBLOCK;
fcntl(socket_fd, F_SETFL, file_status); // Set modified status flags
fcntl(socket_fd, F_SETSIG, SIGIO); // Produce a SIGIO signal when i/o is possible
fcntl(socket_fd, F_SETOWN, getpid()); // Make sure SIGIO signal is sent to current process
The easiest thing to do is just to change stdin over to non blocking. This is done (on Linux and others) by using the fcntl() function to change the F_SETFL option on stdin.
That will make fgetc() (or any other read) no longer block returning right away. If there wasn't any thing to read (no input) it will return an error. If there is something it will return that character.
Here is the call you need to make to change stdin to non-blocking.
fcntl(0, F_SETFL, FNDELAY);
The first argument is the file handle. We pass in 0 which is stdin. The next argument is the option we want to change (in this case F_SETFL), and the 3rd argument is what to change it to (FNDELAY is non-blocking mode).
Here is a simple example program:
#include <stdio.h>
#include <fcntl.h>
void SetupIO(void);
void ShutDownIO(void);
int main(void)
{
long count;
char c;
SetupIO();
count=0;
for(;;)
{
printf("Counting %d\r",count);
count++;
c=fgetc(stdin);
if(c=='q')
break;
}
ShutDownIO();
return 0;
}
void SetupIO(void)
{
fcntl(0, F_SETFL, FNDELAY);
}
void ShutDownIO(void)
{
fcntl(0, F_SETFL, 0);
}
This is great. It no longer blocks, but it still echos the characters being typed and you need to press enter before you will get back any input from fgetc().
If we want to make it more game like we need to tell the terminal to stop messing with our input. We need to switch the terminal into RAW mode.
The following example turn the terminal to RAW mode and changes stdin to non-blocking.
#include <termios.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
void SetupIO(void);
void ShutDownIO(void);
struct termios orig_termios;
int main(void)
{
long count;
char c;
SetupIO();
count=0;
for(;;)
{
printf("Counting %d\r",count);
count++;
c=fgetc(stdin);
if(c=='q')
break;
}
ShutDownIO();
return 0;
}
void SetupIO(void)
{
struct termios new_termios;
/* take two copies - one for now, one for later */
tcgetattr(0, &orig_termios);
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
/* register cleanup handler, and set the new terminal mode */
atexit(ShutDownIO);
cfmakeraw(&new_termios);
new_termios.c_iflag|=INLCR; // CR=NL
new_termios.c_lflag|=ISIG; // We still want Ctrl-C
tcsetattr(0, TCSANOW, &new_termios);
/* Non-blocking */
fcntl(0, F_SETFL, FNDELAY);
}
void ShutDownIO(void)
{
tcsetattr(0, TCSANOW, &orig_termios);
fcntl(0, F_SETFL, 0);
}
The downside to this is that if you Ctrl-C or your program crashes it will leave your terminal in a messed up state that is not easy to get back out of. You can help with this by adding an atexit() and/or signal handling.
Hi I am writing a C program to interface a serial device which gives data at regular intervals, i need to look for the inputs at the serial port at regular intervals. this can be done by a ' read' function . but i dont know how to call it frequently at fixed time intervals ?
This sort of behavior short-circuits the lovely machinery built in to most OSes to do just this, failing that something like cron would seem to be a lovely option. Failing all of that (if you're just looking for a quick hacky option) busy wait is not super awesome, the system isn't bright enough to hyperthread around that so your program winds up eating up a core doing nothing for the duration of your program, so while it's largely a matter of taste, I'm a nanosleep man myself.
on nix/nux systems:
#include <time.h>
int main(void)
{
struct timespec sleepytime;
sleepytime.tv_sec = seconds_you_want_to_sleep
sleepytime.tv_nsec = nanoseconds_you_want_to_sleep
while( !done)
{
nanosleep(&sleepytime, NULL);
//do your stuff here
}
return 0;
}
if you're worried about getting interrupted, the second parameter should be another timespec struct, in which will be stored the amount of time remaining, check if == 0,
then keep on trucking.
in windows apparently it is a little easier.
#include <windows.h>
int main(void)
{
while( !done)
{
Sleep(milliseconds_you_want_to_sleep);
//do your stuff here
}
return 0;
}
Unfortunately I don't run windows so I haven't been able to test the second code sample.
If you really need to read at regular intervals ( and not just poll for data to be available ) , you can do something like this :
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
void timer_handler (int signum)
{
static int count = 0;
printf ("timer expired %d times\n", ++count);
}
int main ()
{
struct sigaction sa;
struct itimerval timer;
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timer_handler;
sigaction (SIGVTALRM, &sa, NULL);
/* Configure the timer to expire after 250 msec... */
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 250000;
/* ... and every 250 msec after that. */
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 250000;
/* Start a virtual timer. It counts down whenever this process is
executing. */
setitimer (ITIMER_REAL, &timer, NULL);
/* Do busy work. */
while (1);
}
I copied this from http://www.informit.com/articles/article.aspx?p=23618&seqNum=14 and changed the timer type, effectively you are setting up an interval timer and handling the signal when the timer runs out.
The main function is based on libevent, but there is a long run task in the function. So start N treads to run the tasks. Is is this idea OK? And how to use libevent and pthread together in C?
Bumping an old question, may have already been solved. But posting the answer just in case someone else needs it.
Yes, it is okay to do threading in this case. I recently used libevent in pthreads, and it seems to be working just fine. Here's the code :
#include <stdint.h>
#include <pthread.h>
#include <event.h>
void * thread_func (void *);
int main(void)
{
int32_t tid = 0, ret = -1;
struct event_base *evbase;
struct event *timer;
int32_t *t_ret = &ret;
struct timeval tv;
// 1. initialize libevent for pthreads
evthread_use_pthreads();
ret = pthread_create(&tid, NULL, thread_func, NULL);
// check ret for error
// 2. allocate event base
evbase = event_base_new();
// 3. allocate event object
timer = event_new(evbase, -1, EV_PERSIST, callback_func, NULL);
// 4. add event
tv.tv_sec = 0;
tv.tv_usec = 1000;
evtimer_add(timer, &tv);
// 5. start the event loop
event_base_dispatch(evbase); // event loop
// join pthread...
// 6. free resources
event_free(timer);
event_base_free(evbase);
return 0;
}
void * thread_func(void *arg)
{
struct event *ev;
struct event_base *base;
base = event_base_new();
ev = event_new(base, -1, EV_PERSIST, thread_callback, NULL);
event_add(ev, NULL); // wait forever
event_base_dispatch(base); // start event loop
event_free(ev);
event_base_free(base);
pthread_exit(0);
}
As you can see, in my case, the event for the main thread is timer. The base logic followed is as below :
call evthread_use_pthreads() to initialize libevent for pthreads on Linux (my case). For windows evthread_use_window_threads(). Check out the documentation given in event.h itself.
Allocate an event_base structure on global heap as instructed in documentation. Make sure to check return value for errors.
Same as above, but allocate event structure itself. In my case, I am not waiting on any file descriptor, so -1 is passed as argument. Also, I want my event to persist, hence EV_PERSIST . The code for callback functions is omitted.
Schedule the event for execution
Start the event loop
free the resources when done.
Libevent version used in my case is libevent2 5.1.9 , and you will also need libevent_pthreads.so library for linking.
cheers.
That would work.
In the I/O callback function delegates time consuming job to another thread of a thread pool. The exact mechanics depend on the interface of the worker thread or the thread pool.
To communicate the result back from the worker thread to the I/O thread use a pipe. The worker thread writes the pointer to the result object to the pipe and the I/O thread
wakes up and read the pointer from the pipe.
There is a multithreaded libevent example in this blog post:
http://www.roncemer.com/multi-threaded-libevent-server-example
His solution is, to quote:
The solution is to create one libevent event queue (AKA event_base) per active connection, each with its own event pump thread. This project does exactly that, giving you everything you need to write high-performance, multi-threaded, libevent-based socket servers.
NOTE This is for libev not libevent but the idea may apply.
Here I present an example for the community. Please comment and let me know if there are any noticable bugs. This example could include a signal handler for thread termination and graceful exit in the future.
//This program is demo for using pthreads with libev.
//Try using Timeout values as large as 1.0 and as small as 0.000001
//and notice the difference in the output
//(c) 2009 debuguo
//(c) 2013 enthusiasticgeek for stack overflow
//Free to distribute and improve the code. Leave credits intact
//compile using: gcc -g test.c -o test -lpthread -lev
#include <ev.h>
#include <stdio.h> // for puts
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t lock;
double timeout = 0.00001;
ev_timer timeout_watcher;
int timeout_count = 0;
ev_async async_watcher;
int async_count = 0;
struct ev_loop* loop2;
void* loop2thread(void* args)
{
// now wait for events to arrive on the inner loop
ev_loop(loop2, 0);
return NULL;
}
static void async_cb (EV_P_ ev_async *w, int revents)
{
//puts ("async ready");
pthread_mutex_lock(&lock); //Don't forget locking
++async_count;
printf("async = %d, timeout = %d \n", async_count, timeout_count);
pthread_mutex_unlock(&lock); //Don't forget unlocking
}
static void timeout_cb (EV_P_ ev_timer *w, int revents) // Timer callback function
{
//puts ("timeout");
if(ev_async_pending(&async_watcher)==false){ //the event has not yet been processed (or even noted) by the event loop? (i.e. Is it serviced? If yes then proceed to)
ev_async_send(loop2, &async_watcher); //Sends/signals/activates the given ev_async watcher, that is, feeds an EV_ASYNC event on the watcher into the event loop.
}
pthread_mutex_lock(&lock); //Don't forget locking
++timeout_count;
pthread_mutex_unlock(&lock); //Don't forget unlocking
w->repeat = timeout;
ev_timer_again(loop, &timeout_watcher); //Start the timer again.
}
int main (int argc, char** argv)
{
if (argc < 2) {
puts("Timeout value missing.\n./demo <timeout>");
return -1;
}
timeout = atof(argv[1]);
struct ev_loop *loop = EV_DEFAULT; //or ev_default_loop (0);
//Initialize pthread
pthread_mutex_init(&lock, NULL);
pthread_t thread;
// This loop sits in the pthread
loop2 = ev_loop_new(0);
//This block is specifically used pre-empting thread (i.e. temporary interruption and suspension of a task, without asking for its cooperation, with the intention to resume that task later.)
//This takes into account thread safety
ev_async_init(&async_watcher, async_cb);
ev_async_start(loop2, &async_watcher);
pthread_create(&thread, NULL, loop2thread, NULL);
ev_timer_init (&timeout_watcher, timeout_cb, timeout, 0.); // Non repeating timer. The timer starts repeating in the timeout callback function
ev_timer_start (loop, &timeout_watcher);
// now wait for events to arrive on the main loop
ev_loop(loop, 0);
//Wait on threads for execution
pthread_join(thread, NULL);
pthread_mutex_destroy(&lock);
return 0;
}
Can someone help me to complete my code with a function that can check the result of a timer "check_timer" and another one that reset this timer if it had expired "reset_timer"?
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <sys/time.h>
#define GLOBAL_TIMER 8 * 60 * 60
typedef struct protocol_type {
int protocol_number;
char *protocol_name;
pthread_t thread_timer_id;
} protocol_type_t;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
/* call back function - inform the user the time has expired */
void timeout_call_back(pthread_t thread_id)
{
printf("Welcome thread %ld, your time is up ===\n", pthread_self());
// doing some other stuff
}
/* Go to sleep for a period of seconds */
static void* start_timer(void *args)
{
/* function pointer */
void (*finish_function)(pthread_t);
int seconds = *((int*) args);
finish_function = timeout_call_back;
struct timeval now;
struct timespec timeout;
pthread_mutex_lock(&mut);
printf("thread ID : %ld, are waiting for %d seconds to to expire\n", pthread_self(), seconds);
gettimeofday(&now, NULL);
timeout.tv_sec = now.tv_sec + seconds;
timeout.tv_nsec = now.tv_usec * 1000;
pthread_cond_timedwait(&cond, &mut, &timeout);
(*finish_function)(pthread_self());
pthread_mutex_unlock(&mut);
pthread_exit(NULL);
}
// This function is in MT environnement and is running inside a daemon
int received_buffer_parser(char *received_buffer) {
pthread_mutex_t mut_main = PTHREAD_MUTEX_INITIALIZER;
protocol_type_t *my_protocol;
// Identify protocol type
my_protocol = protocol_identifier(received_buffer);
// Check if i received it in the last 8 hours in safe
pthread_mutex_lock(&mut_main);
if (check_timer(my_protocol->thread_id) has expired) { // I want to write this function
// I want to reset thread timer
launch_new_timer(my_protocol->thread_id)
}
else {
// doing some stuff
// dump data to the disk
}
pthread_mutex_unlock(&mut_main);
return 0;
}
int launch_new_timer(pthread_t thread_id)
{
int rc;
int seconds = GLOBAL_TIMER;
rc = pthread_create(&thread_id, NULL, start_timer, (void *) &seconds);
if(rc)
printf("Failed to create thread1\n");
pthread_join(thread_id, NULL);
return 0;
}
Clarification
I clarify here the real context of my code:
I receive from the network some types of different protocols packets(ICMP, SSH, RIP, OSPF, BGP...), and i want to:
identify every type of packets, let say with : identify_protocol(char *received_buffer), I got this function, it's ok.
Check if i receive this type of protocols in the last 8 hours (THE TIMER OF EACH PROTOCOL TYPE EXPIRE AFTER 8 HOURS), two choices:
a. if so, I dump the result data into a specific file on the disk.
b. no, I didn't receive this type in the last 8 HOURS i create a new thread (in my code i simplify, with thread1, thread2 and thread3, this threads are 3 threads used to be a timers for three protocols types) - i start a new timer with : start_timer(void *args) function do this job.
My main question is how to be able to check the result of my timers in a safe manner and then decide i reset the timer or not.
I design the finish_function at the beginning to help me to check when the timer has expired.
Feel free to give me a better design for best performances for my program.
My system is Linux.
To check for timers that merely expire, you don't need to use threads and synchronization at all. Simply keep global variables indicating the start time of the timer. So
when the timer starts, set a global variable (one per protocol) to gettimeofday()
when you want to check whether the timer has expired for a protocol, see whether gettimeofday()-starttime(protocol) is <8h
If you want to be notified on timer expiry, I recommend to use alarm(2). It only has second resolution, but that should be good enough for 8h timeouts. Whenever a timer is set, cancelled, or reset, compute the minimum timeout of any of the timers, then call alarm with that timeout. In the signal handler, perform the processing that you want to do on reception of timeout. Alternatively, do nothing in the signal handler, and just trust that any pending system call will be interrupted, and check all timers for expiry on EINTR.
Edit: alarm works like this
#include <unistd.h>
#include <signal.h>
void timeout(int ignored)
{
printf("timed out\n");
}
void main()
{
signal(SIGALRM, timeout);
alarm(10);
pause();
}