2011-08-25 20 views
14

Siempre noto que las personas tienen diferentes reacciones a las diferentes formas de crear un temporizador en UNIX.La mejor manera de hacer un temporizador en UNIX

sé algunas maneras diferentes que podía hacer un evento ejecute cada X segundos dentro de UNIX:

  • se puede hacer un hilo de votación - pthread_t con duerme;
  • puede hacer una selección() con un tiempo de espera;
  • y supongo que puede usar el sistema operativo de algunas otras maneras.

¿Alguien puede proporcionar un código de muestra con la "mejor" o la forma más eficiente de hacer un temporizador y una descripción de por qué es el mejor? Me gustaría utilizar el mecanismo más eficiente para esto, pero no estoy seguro de cuál es.

Para nuestros propósitos, pretenda que está imprimiendo "¡Hola, mundo!" una vez cada 10 segundos

NOTA: No tengo TR1/Boost/etc. en este sistema, por lo tanto, guárdelo en llamadas directas al sistema C/C++ y UNIX. Perdón por no mencionar eso la primera vez :)

+0

la programación de un solo subproceso es más fácil que un concurrente, por lo que si se puede garantizar que sus llamadas regulares no superen el intervalo, me gustaría ir con un simple tiempo de espera (como con 'select()'). Sin embargo, necesitarás multihilo, si las llamadas en sí tardan más y tu temporizador tiene que disparar nuevamente antes de que las llamadas regresen. –

+0

El sistema ya usa mucho el multihilo para que no haya problema. Mezcle como una respuesta :) –

+0

Hm, realmente no tengo nada que decir sobre la pregunta real. He usado boost.asio para mis necesidades de sincronización antes (con el bucle ioservice ejecutándose en un hilo separado), pero no puedo hablar de las ventajas comparativas de los diversos enfoques ... –

Respuesta

5

Depende de lo que están queriendo hacer. Un sueño simple será suficiente para su ejemplo trivial de esperar 10 segundos entre "Hola" ya que también podría suspender su hilo actual hasta que se acabe el tiempo.

Las cosas se vuelven más complicadas si el hilo realmente está haciendo algo mientras espera. Si está respondiendo a las conexiones entrantes, ya estará usando select en tal caso, un tiempo de espera para su declaración select tiene más sentido para su mantenimiento.

Si está procesando cosas en un circuito cerrado, puede sondear regularmente una hora de inicio para ver si los 10 segundos están activos.

alarm con un manejador de señal apropiado funcionará también, pero hay límites severos a lo que puede hacer en un controlador de señal. La mayoría de las veces, implicó establecer una bandera que deberá ser consultada cada cierto tiempo.

En pocas palabras, se trata de cómo el hilo procesa los eventos.

2

Si su programa ya está enhebrado, entonces usar un hilo de encuesta es simple y efectivo.

Si su programa aún no está enhebrado, entonces se vuelve más complicado. ¿Puedes usar un proceso separado para hacer el trabajo? Si es así, entonces use multiprocesamiento en lugar de multi-threading.

Si no puede usar un hilo de control autónomo (proceso o hilo), depende de cómo esté organizado su programa, por lo que hay muchas alternativas preferidas (se prefieren para diferentes circunstancias). También depende de la precisión del tiempo que requiera. Con brechas de varios segundos y sin requisitos de respuesta en tiempo real, puede usar una alarma y el controlador SIGALRM puede establecer una bandera y su bucle de procesamiento principal puede monitorear la bandera en puntos convenientes y sensibles y realizar la actividad. Esto es algo desordenado (porque las señales son desordenadas), pero sin una descripción más detallada de sus requisitos y limitaciones, es difícil saber qué más sugerir.

Por lo tanto, en resumen, no hay una única solución universalmente mejor porque los diferentes programas se escriben en diferentes estilos y bajo diferentes restricciones.

+0

+1: Muy bonito .. –

+0

Además de los costos en la dependencia de la biblioteca, el viraje en el procesamiento múltiple de una aplicación es ** mucho más trabajo ** para obtener derecho a virar en multi-threading. Errores de módulo en la implementación pthread, la creación de un hilo desde un punto en la aplicación debe ser completamente transparente para el resto de la aplicación. Por otro lado, agregar un proceso requiere tratar con 'SIGCHLD', pid y esperar/salir de la administración de estado, etc. –

3

utilizar un bucle dirigido por eventos como Boost.Asio

#include <iostream> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp> 

class Timer 
{ 
public: 
    Timer(
      boost::asio::io_service& io_service 
     ) : 
     _impl(io_service) 
    { 
     this->wait(); 
    } 

private: 
    void wait() 
    { 
     _impl.expires_from_now(boost::posix_time::seconds(10)); 
     _impl.async_wait(
       boost::bind(
        &Timer::handler, 
        this, 
        _1 
        ) 
       ); 
    } 

    void handler(
      const boost::system::error_code& error 
      ) 
    { 
     if (error) { 
      std::cerr << "could not wait: " << boost::system::system_error(error).what() << std::endl; 
      return; 
     } 

     std::cout << "Hello World!" << std::endl; 

     this->wait(); 
    } 

private: 
    boost::asio::deadline_timer _impl; 
}; 

int main() 
{ 
    boost::asio::io_service io; 

    Timer t(io); 

    io.run(); 

    return 0; 
} 

acumulación & de ejecución:

stackoverflow samm$ ./a.out 
Hello World! 
Hello World! 
Hello World! 
^C 
stackoverflow samm$ 
+1

Me encanta esa respuesta, pero desafortunadamente no tengo TR1/Boost disponible para mí, además de que me gustaría algo es un sistema operativo o basado en C directo, por lo que es más portátil. Lo votó aunque es una buena solución :) –

+0

Agradable; ¡y esto puede ser fácilmente multiproceso si es necesario al poner 'run()' en un hilo separado! –

+1

@ w00te: si quieres algo "C directo", ¡no etiquetes tu pregunta "C++"! –

1

Las opciones de cómo hacer un temporizador varían en cuanto a facilidad de uso, portabilidad, precisión, fealdad (estado global/señales) y adecuación para aplicaciones en tiempo real. Personalmente, para el mejor de los mundos, recomendaría rodar su propio temporizador con un hilo, y usar clock_nanosleep con la bandera TIMER_ABSTIME y la fuente de reloj CLOCK_MONOTONIC. De esta forma, puede evitar el error acumulado y las discontinuidades al establecer la hora del sistema, y ​​puede contar los excesos usted mismo. En teoría, POSIX timer_create con entrega SIGEV_THREAD debería darle las mismas propiedades, pero la implementación de glibc es realmente mala y no puede garantizar que no perderá los eventos de vencimiento del temporizador bajo carga pesada.

+0

No sabía que 'SIGEV_THREAD' se considera poco confiable. ¿Eso proviene de la experiencia personal, o hay un informe de error en alguna parte? – cnicutar

+0

Viene de leer la fuente (incluidos los comentarios que documentan la falla). Llama a 'malloc' y' pthread_create' para cada entrega, y si falla, la entrega se perderá y no se informará en 'timer_getoverrun'. La implementación más segura es tener un hilo persistente para el temporizador que se reutiliza para cada entrega, pero esto requiere algunos hacks e interacción con la implementación de hilos para que 'pthread_exit' y' pthread_cancel' funcionen y oculten el hecho de que el hilo se está reutilizando. –

+0

Gracias por la información, apreciado :-) – cnicutar

1

sleep() es la forma más fácil. usleep() existe en algunas variantes. Si desea una precisión de menos de segundo, seleccione (NULL, NULL, NULL & timeout) es el más portátil, a menos que escriba sus propias rutinas específicas del sistema operativo. El método select() tiene la ventaja de que el tiempo de espera se actualiza para reflejar la cantidad de tiempo restante si la llamada fue interrumpida por una señal. Puede reanudar la espera si es necesario.

Realmente, todos los métodos son equivalentes; el sistema operativo deja de programar el hilo para el período de tiempo de espera.

El método SIGALARM sugerido por Blagovestus es (algo) imposible de usar, aunque debería funcionar en Linux.

0

Si solo tiene que emitir "Hello world" una vez cada 10 segundos, supongo que dormir y nanosleeps funcionarán. Si sus tareas son de alguna manera más críticas, podría echarle un vistazo a RealTime Linux. No (www.ee.nmt.edu/~rison/ee352_fall09/Getting_Started_with_RTLinux.pdf) le dieron una buena guía sobre eso. Al usar RTLinux puede usar pthread_make_periodic_np para hacer una tarea periódica, aunque usted será el que se encargará de asegurarse de que se cumplan las condiciones de tiempo real.

1

Esta es una respuesta tardía, pero quería agregar mi implementación de un temporizador. Es un temporizador con subprocesos, y necesita algo de trabajo, con el fin de mutexes y pthreads en sus propias clases (falta de RAII en ese sentido). Tampoco es multiplataforma ya que utiliza el método gettimeofday().

El código utiliza un temporizador que llama a un objeto CallBack. La fuente completo puede ser visto en

http://matthewh.me/playground/browser/branches/C%2B%2B/c%2B%2B_callbacks

+1

Bueno, ahora estoy en el mundo de C#, pero la respuesta es aún apreciada :) Es un código agradable, así que estoy seguro de que será útil para alguien que busque esto pregunta. –

Cuestiones relacionadas