2010-10-25 67 views
12

Estoy desarrollando una aplicación multiproceso que hace uso de POSIX Threads. Estoy utilizando hilos para hacer un trabajo periódico y para ese propósito estoy usando usleep(3) para suspender la ejecución del hilo. Mi pregunta es cómo puedo cancelar el temporizador usleep() desde el hilo principal, probé pthread_kill(thread, SIGALRM) pero tiene un efecto global que da como resultado la finalización de la aplicación principal (por defecto). Aquí está mi seudo código:Dormir en un hilo (Hilos C/POSIX)

void threaded_task(void *ptr) { 
    initialize(); 

    while(running) { 
     do_the_work(); 
     usleep(some_interval); 
    } 

    clean_up(); 
    release_resources(); 
} 

Y aquí es la función seudo que se utiliza para detener (y apagado de precaución) dada hilo del hilo principal:

void stop_thread(pthread_t thread) { 
    set_running_state(thread, 0); // Actually I use mutex staff 
    // TODO: Cancel sleep timer so that I will not wait for nothing. 
    // Wait for task to finish possibly running work and clean up 
    pthread_join(thread, NULL); 
} 

Cuál es el manera conveniente de lograr mi objetivo? ¿Tengo que usar variables condicionales o puedo hacerlo usando las variantes de sleep()?

Respuesta

9

USe select() con un FIFO o un zócalo que puede extraer para activarlo.

+0

Select es un pequeño sueño idiomática UNIX (y puede ser pinchado con una FIFO) –

2

Como alternativa a select, también es posible utilizar variables de condición pthread (ver pthread_cond_init, pthread_cond_wait, y pthread_cond_signal), semáforos SysV, o semáforos POSIX. Todos ellos se adaptan mejor que nosotros para un hilo de procesamiento de eventos.

+0

Dado que estoy usando usleep() para la suspensión, el uso de variables de condición (y mutex extra) no es deseable para mí. –

2

Parece que se está ejecutando en Linux desde la página de manual referenciada. Debería poder usar nanosleep e interupt con una aplicación determinada (SIGRTMIN + x) para el proceso secundario. Nanosleep tiene la funcionalidad de ser interrumpida por señales y devolver el tiempo restante que se suponía que había dormido. También puede usar el modo dormir si está usando periodos de tiempo más largos para dormir.

nanosleep(2)

signal(7)

Cualquier tipo de IPC ha mencionado anteriormente, también podría ayudar a resolver este problema.

EDIT: Parece que ya está haciendo esto, excepto que debe utilizar una señal que no tendrá efectos externos en el programa. Cualquiera de las funciones de reposo debe ser interrumpida por una señal no bloqueada. Las señales en tiempo real están destinadas a ser utilizadas por aplicación.

2

Hay un número de maneras de hacer esto:

  • Uso truco auto-pipe @Ignacio menciona (Linux proporciona útil, pero no es portátil, eventfd(2) a sustituir las tuberías aquí)
  • hilos conectarse a través de colas de bloqueo construido alrededor de mutex y variables condicionales, esperar en cola vacía, Encendido en elemento en la cola
  • señales de bloque en hilo principal antes de comenzar otros hilos, esperar la señal, activación de la señal - ver pthread_sigmask(3)
4

Utilizamos una espera de una condición variable con un tiempo de espera utilizando pthread_cond_timedwait

Cuando queremos apagado establecemos un 'Apagando' variable y hacer un pthread_cond_broadcast

+0

Esto es lo que yo recomendaría también. –

5

La razón de que SIGALRM está matando al toda la aplicación es que probablemente no haya registrado un manejador de señal para ello. La acción predeterminada para SIGALRM es que el kernel finalice el proceso, por lo que si usleep se implementa de una manera que no utiliza SIGALRM (usando nanosleep o una de las funciones de sondeo con tiempo de espera, por ejemplo) entonces usleep no habría registrado un controlador o de otro modo cambió la disposición predeterminada de la señal.

void handle_alrm(int sig) { 
} 

... 

int main(void) { 
    signal(SIGALRM, handle_alrm); 
    ... 

debería ser suficiente para mantener su programa de matar, aunque usted debe buscar en la función más complicada sigaction en lugar de signal ya que permite un mayor control y se comporta de forma más consistente a través de diferentes plataformas.

Esto puede causar problemas si luego intenta utilizar el código en un sistema que sí utiliza SIGALRM para implementar usleep o sleep, por lo que puede desear simplemente no usar las versiones de biblioteca estándar de esas y usar funciones que tengan una implementación más predecible en todas las plataformas (posiblemente una envoltura delgada alrededor de nanosleep que proporciona la interfaz que desea).

+2

Las implementaciones de 'sleep' o' usleep' con 'SIGALRM' no son conformes, por POSIX. –

6

También puede dormir con un semáforo (de hecho, es su verdadero propósito).

a sema_wait en su hilo y sema_post en su hilo principal. Es fácil, está limpio, es portátil. Aquí un enlace a un artículo que detalla el procedimiento: http://www.netrino.com/node/202

+0

sema_wait y sema_post son para fines de sincronización, aunque mi problema está relacionado con la sincronización, no es un problema de exclusión mutua. –

+0

Lee el artículo vinculado? Los semáforos también sirven para señalizar, no porque la mayoría de la gente los use indebidamente como mutexes y no pueden ser utilizados para su verdadero propósito. –

+0

Sea lo que sea que estés durmiendo, la condición en sí misma es probablemente un semáforo. – Ajax

2

Tal vez necesita meterse con la máscara de señal o tal vez las señales no pueden salir de nosotros ... No sé. No sé si podría usar sigwait() o sigtimedwait(). Usamos pthread_kill para despertar hilos, pero los dormimos usando sigwait ... not usleep. Esta es la manera más rápida que he encontrado para hacer esto despierte

Hacemos esto antes de crear hilos (40-50x más rápido que esperar en una pthread_cond según mis pruebas.):

hereda
int fSigSet; 
sigemptyset(&fSigSet); 
sigaddset(&fSigSet, SIGUSR1); 
sigaddset(&fSigSet, SIGSEGV); 
pthread_sigmask(SIG_BLOCK, &fSigSet, NULL); 

Cada hilo creadas esta máscara Me confundo un poco con las máscaras. Le está diciendo al sistema que no haga nada por ciertas señales o tal vez le está diciendo al sistema que está manejando algunas señales ... No sé. Alguien más puede conectarnos y ayudarnos. Si conozco mejor cómo funcionaban las máscaras, podría decirte que podrías pegar el código anterior en tu ThreadProc. Además, no estoy seguro si SIGSEGV es necesario.

A continuación, un subproceso llama a esto a dormir en sí:

int fSigReceived; 
// next line sleeps the thread 
sigwait(&fSigSet, &fSigReceived); // assuming you saved fSigSet from above... 
// you get here when the thread is woken up by the signal 
// you can check fSigReceived if you care what signal you got. 

Entonces usted esto a raíz de un hilo:

thread_kill(pThread, SIGUSR1); 
Cuestiones relacionadas