Sveglia ripetitiva efficiente in linguaggio a basso livello come C

1

Ci stavo pensando ed ero curioso di sapere come si codificasse una sveglia a ripetizione efficiente in C? Vuoi impostare un orario di sveglia e quindi compensare il tempo con l'equivalente tempo ms di un giorno (o due giorni o una settimana a seconda di quanto spesso è necessario ripetere)? E poi sondare periodicamente per vedere se i tempi sono uguali? Sembra una soluzione molto inefficiente, almeno per me. Ero interessato a come una sveglia avrebbe funzionato in modo programmatico.

    
posta cg14 23.01.2016 - 17:23
fonte

2 risposte

4

Ci sono molti modi per ottenere questo risultato, tutto a seconda del tipo di ambiente con cui stai lavorando. Un'altra preoccupazione è ovviamente la latenza che ti puoi permettere.

Se stai lavorando su un sistema operativo moderno, molto probabilmente hai un'API che metterà il thread in attesa fino a quando non sarà arrivato il momento. Posix ha nanosleep() e C11 ha la funzione thread_sleep() per fare questo.

Se utilizzi sistemi operativi più primitivi o programmati direttamente per l'hardware incorporato, potresti dover ricorrere ad attendere interruzioni periodiche, o anche usare loop occupati.

Aggiornamento: per gestire più allarmi utilizzando l'approccio thread_sleep() , potresti ad esempio memorizzare tutti gli avvisi in arrivo in un elenco ordinato. Dormi finché non scatta il primo allarme, fai quello che devi fare e poi calcola il tempo fino al prossimo allarme e torna a dormire. Questo approccio utilizza solo un thread del timer, che sarà molto efficiente purché soddisfi i requisiti di latenza.

    
risposta data 23.01.2016 - 17:58
fonte
1

per un timer ripetuto.

Usa setitimer()

qui ci sono informazioni dalla pagina man

    NAME
           getitimer, setitimer - get or set value of an interval timer

    SYNOPSIS
           #include <sys/time.h>

           int getitimer(int which, struct itimerval *curr_value);
           int setitimer(int which, const struct itimerval *new_value,
                         struct itimerval *old_value);

    DESCRIPTION
           The  system  provides  each  process  with  three interval timers, each
           decrementing in a distinct time domain.  *When any timer expires, a sig‐
           nal is sent to the process*, and the timer (potentially) restarts.

           ITIMER_REAL    decrements in real time, and delivers SIGALRM upon expi‐
                          ration.

           ITIMER_VIRTUAL decrements only  when  the  process  is  executing,  and
                          delivers SIGVTALRM upon expiration.

           ITIMER_PROF    decrements  both  when the process executes and when the
                          system is executing on behalf of the  process.   Coupled
                          with  ITIMER_VIRTUAL, this timer is usually used to pro‐
                          file the time spent by the application in user and  ker‐
                          nel space.  SIGPROF is delivered upon expiration.

           Timer values are defined by the following structures:

               struct itimerval {
                   struct timeval it_interval; /* next value */
                   struct timeval it_value;    /* current value */
               };

               struct timeval {
                   time_t      tv_sec;         /* seconds */
                   suseconds_t tv_usec;        /* microseconds */
               };

           The  function  getitimer() fills the structure pointed to by curr_value
           with the current setting for the  timer  specified  by  which  (one  of
           ITIMER_REAL,  ITIMER_VIRTUAL, or ITIMER_PROF).  The element it_value is
           set to the amount of time remaining on the timer, or zero if the  timer
           is disabled.  Similarly, it_interval is set to the reset value.

           The  function  setitimer()  sets  the  specified  timer to the value in
           new_value.  If old_value is non-NULL, the old value  of  the  timer  is
           stored there.

           Timers decrement from it_value to zero, generate a signal, and reset to
           it_interval.  A timer which is set to zero (it_value  is  zero  or  the
           timer expires and it_interval is zero) stops.

           Both  tv_sec and tv_usec are significant in determining the duration of
           a timer.

           Timers will never expire before the requested time, but may expire some
           (short)  time  afterward,  which depends on the system timer resolution
           and on the system load; see time(7).  (But see BUGS below.)  Upon expi‐
           ration,  a  signal will be generated and the timer reset.  If the timer
           expires while the process is active (always  true  for  ITIMER_VIRTUAL)
           the signal will be delivered immediately when generated.  Otherwise the
           delivery will be offset by a small time dependent on the  system  load‐
           ing.

    RETURN VALUE
           On  success,  zero is returned.  On error, -1 is returned, and errno is
           set appropriately.

    ERRORS
           EFAULT new_value, old_value, or curr_value is not valid a pointer.

           EINVAL which is not one of ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF;
                  or  (since Linux 2.6.22) one of the tv_usec fields in the struc‐
                  ture pointed to by new_value contains a value outside the  range
                  0 to 999999.

    CONFORMING TO
           POSIX.1-2001,  SVr4,  4.4BSD  (this  call  first  appeared  in 4.2BSD).
           POSIX.1-2008 marks getitimer() and setitimer()  obsolete,  recommending
           the  use  of  the POSIX timers API (timer_gettime(2), timer_settime(2),
           etc.) instead.

    NOTES
           A child created via fork(2) does  not  inherit  its  parent's  interval
           timers.  Interval timers are preserved across an execve(2).

           POSIX.1 leaves the interaction between setitimer() and the three inter‐
           faces alarm(2), sleep(3), and usleep(3) unspecified.

           The standards are silent on the meaning of the call:

               setitimer(which, NULL, &old_value);

           Many systems (Solaris, the BSDs, and  perhaps  others)  treat  this  as
           equivalent to:

               getitimer(which, &old_value);

           In  Linux,  this  is treated as being equivalent to a call in which the
           new_value fields are zero; that is, the timer is disabled.   Don't  use
           this Linux misfeature: it is nonportable and unnecessary.
    
risposta data 25.01.2016 - 03:53
fonte

Leggi altre domande sui tag