2012-06-29 20 views
9

Bien, entonces esta pregunta no es exactamente sobre administración de hilos ... bueno, más o menos. Estoy buscando diferentes soluciones a esta configuración. Tengo algunas ideas, pero estoy buscando soluciones que puedan satisfacer el problema. Y sopesará los pros y los contras para implementar el mejor.Necesito implementar una forma de dormir este hilo hasta que tenga trabajo que hacer

Aquí está la situación.

Tengo una aplicación de administrador que engendrará un subproceso. Este subproceso se ejecutará continuamente y manejará la comunicación en serie con las placas que están conectadas al sistema a través de USB. La aplicación de administrador facilita la comunicación entre otras aplicaciones que se ejecutan en el sistema y este hilo. El hilo necesita para llevar a cabo realmente dos cosas:

  1. Poll, las tablas para datos de la muestra a través de serie de un temporizador variable de .. por lo general una vez por minuto (el bus serie es bastante lento, baudios es 4800. No puedo controlar esto)
  2. Facilite la comunicación con la aplicación de administrador. (es decir, otras aplicaciones solicitarán datos de muestra, el administrador reenvía la solicitud al hilo. el hilo realiza la operación y devuelve los datos)

Mi diseño inicial era simple y funciona. Uso una cola y un mutex para que el administrador entable la comunicación. Así que la lógica de la rosca es la siguiente:

  1. inicialización
  2. Aunque no hemos recibido un comando de apagado desde el gestor de
  3. Si nuestro contador de tiempo se ha terminado, sondee el tablero para los datos
  4. De lo contrario, verifique si tenemos un mensaje publicado por el gerente en la cola. si es así, trátelo

El problema es que no consideré la utilización de la CPU. El 99.9% de las veces mi hilo no procesa nada y solo absorbe energía. Necesito implementar una forma de dormir este hilo hasta que tenga trabajo por hacer. Entonces un par de ideas:

Use seleccionar() para bloquear. Esto se puede bloquear en función del temporizador que necesito usar, y podría cambiar la implementación de la mensajería en cola al socket de mensajes. Por lo tanto, en su lugar, el subproceso abriría un socket de cliente al administrador y el administrador pasaría los mensajes por el socket al subproceso . Luego, seleccionar() dormiría hasta que hubiera actividad en el fd o mi temporizador estuviera activado.

Pro: Exactamente la funcionalidad que necesito.

Con: ¿No son los zócalos un procesamiento algo pesado para la comunicación a un hilo en el que usted ya comparte memoria?

Utilice un sistema de señal. (Alguien más conocedor de Linux puede usar aquí un ejemplo de implementación ... No estoy seguro de cómo hacerlo exactamente ). Pero el hilo podría dormir durante la duración del temporizador, y se activa para procesar si la señal fue recibida del gerente.

Pro: Mantiene la implementación actual el uso de memoria compartida

En contra: No estoy seguro de cómo poner en práctica. ¿Hay alguna función como select() que funcione con señales en lugar de fds?

Potencialmente un mutex. Podría bloquear hasta que el administrador haya enviado un mutex.

Pro: Aún compartiendo memoria

contra: puede necesitar mover el procesamiento de temporizador con el gerente y que realmente no es una opción, ya que tiene otros temporizadores y trabajo crítico para llevar a cabo.

Por favor, siéntase libre de criticar. Estoy abierto a cualquier opción eficiente. Tenga en cuenta que esto se está ejecutando en un sistema integrado, por lo que el uso de recursos es crítico.

+3

¿Por qué no utilizar una variable condicional cuando tiene que esperar un evento? El hilo se pone efectivamente en modo reposo hasta que la variable sea señalada por otro hilo. – Tudor

+0

Absolutamente podría, pero el punto es que no quiero procesar nada. No quiero verificar repetidamente el valor de una variable que va a cambiar una vez por minuto. Eso es un montón de sobrecarga. Quiero que el subproceso duerma para que pierda tiempo de CPU. – linsek

+1

Asegúrese de evitar esto: http://stackoverflow.com/questions/3886171/why-thread-sleep-is-so-cpu-intensive –

Respuesta

3

intentar algo como esto, el uso de semáforos:

#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <semaphore.h> 

static sem_t s_sem; 
static int iAlive = 1; 

void* thFunc(void *param) 
{ 
    printf("%s : ENTER \n", __FUNCTION__); 
    while(iAlive) 
    { 
     printf("%s : waiting \n", __FUNCTION__); 
     sem_wait(&s_sem); 

     printf("%s : got a signal - doing something \n", __FUNCTION__); 
     sleep(1); 
    } 

    printf("%s : EXIT \n", __FUNCTION__); 
    return 0; 
} 

int main() 
{ 
    pthread_t thread; 
    sem_init(&s_sem, 0, 0); 

    if(0 != pthread_create(&thread, NULL, thFunc, NULL)) 
    { 
     printf("%s : pthread_create FAILED \n", __FUNCTION__); 
     return -1; 
    } 

    while (getchar() != 'q') 
    { 
     printf("%s : sending signal \n", __FUNCTION__); 
     sem_post(&s_sem); 
    } 

    iAlive = 0; 
    sem_post(&s_sem); 
    pthread_join(thread, NULL); 
    sem_destroy(&s_sem); 

    return 0; 
} 

Puede reemplazar sem_wait con sem_timedwait si necesita un tiempo de espera.

3

Haga que cada subproceso espere en una cola de productor-consumidor de entrada con un tiempo de espera agotado. Si la cola agota el tiempo de espera, sondee el enlace en serie, de lo contrario, procese el comando recibido en la cola. Para formar una cola adecuada desde cero, necesita una cola real, (que ya tiene), un mutex para proteger los punteros/índices de cola, (que ya tiene), y un semáforo, inicializado a 0, con una espera (tiempo de espera) función. Para enviar una solicitud al hilo, bloquee el mutex, presione la solicitud, desbloquee el mutex, señale el semáforo. En el hilo, espere en el semáforo, si la espera vuelve sin tiempo de espera, bloquee el mutex, muestre la solicitud, (porque siempre habrá una), desbloquee el mutex y procese la solicitud recibida. Si la espera de sema vuelve con un tiempo de espera, sondear el enlace en serie. Cuando termine, gire para esperar nuevamente en el semáforo.

Para variar el tiempo de espera, envíe un mensaje al subproceso con el comando 'EchangeWaitInterval', (por ejemplo :), y el nuevo intervalo de tiempo de espera que se utilizará para las esperas posteriores.

4

Cambie las colas de mensajes POSIX en lugar de las suyas. mq_timedreceive devolverá si el administrador publica una solicitud. Si se agota el tiempo, tienes que hacer tu votación con temporizador. La sincronización y el bloqueo vienen ya empaquetados.

+0

Sí, eso debería hacer. –

+0

un poco demasiado pesado, los semáforos son un poco más simples. –

5

La herramienta clásica para manejar tales situaciones son semáforos y no mutexes o variables de condición. Piense en ellos como fichas pasadas del gerente al hilo.

El hilo podría usar sem_timedwait para asegurarse de despertarse de vez en cuando para verificar los datos.

Tenga cuidado para capturar los retornos de error de sem_ funciona bien, son interrumpibles. Por lo tanto, es posible que tengas un poco más de wake ups de lo que piensas.

+0

Un par de semáforos responde aquí, así que solo responderá a todos aquí. ¿Usaría un semáforo como temporizador para despertar y verificar que los datos fueran más eficientes que bloquear con select() y recibir los datos en un socket? Por un lado, estoy usando memoria compartida en lugar de recv(), pero por el otro, si nunca recibo una solicitud de otra aplicación. Estoy procesando sin ninguna razón. – linsek

+0

Al describir su problema, el hecho de que su hilo no duerma es realmente significativo. Esto significa que si lo das vuelta, tu hilo no está haciendo mucho trabajo en comparación con eso. Entonces, si domina este problema de "suspensión", la solución que tome no tendrá mucho impacto en el trabajo general (ciclos de CPU) que utiliza el subproceso. Las diferencias están entonces en (1) conveniencia, lo que está programado y mantiene la latencia más fácil (2). Para ambos, creo que los semáforos ganan. –

+0

Las esperas del semáforo están bloqueando. Si aún no se ha agotado el tiempo de wait() y el semáforo aún no se ha señalizado y su recuento interno es cero, no se utiliza ninguna CPU. La espera sem (tiempo de espera) simplemente no regresará hasta que se cumpla una condición o la otra. Si la espera se agota, el thred se ejecutará una vez. Si el semáforo es señalado 15 veces por los mensajes de cola del administrador, el hilo se ejecutará 15 veces y procesará los 15 y no más. –

0

El enfoque pthreads clásico para esto sería tener su bloque de hilos en pthread_cond_wait() hasta que el hilo del administrador ponga un mensaje en la cola y señalice la variable de condición. En este caso, para despertar de manera oportuna para sondear los dispositivos seriales, use pthread_cond_timedwait() en su lugar.

Cuestiones relacionadas