2012-09-27 45 views
8

Estoy ejecutando este programa donde tengo varios hilos. Tres hilos generan señales para el mismo proceso principal. Hay cuatro hilos de manipulador para manejar las señales generadas por los hilos de generación de señal. Tengo un hilo de monitoreo que también recibe las señales y los procesos de acuerdo. Sin embargo, tengo una situación. Puedo ver que las señales no están divididas por igual. Quiero decir que las señales están dirigidas al mismo proceso. Tengo cuatro subprocesos de controlador y un subproceso de monitoreo esperando la señal. Entonces cualquiera de ellos puede recibir la señal. Esperaba que se distribuyera de manera uniforme. Sin embargo, pude ver que en el momento se reciben una ráfaga completa de señales por los hilos del manejador. La próxima vez toda la ráfaga de señales es manejada por el hilo del monitor. Por qué no es uniforme He agregado una llamada de suspensión después de que los hilos del controlador/monitor completen el manejo de una señal. Entonces, tan pronto como el controlador/monitor complete una señal, debería haber dado la otra oportunidad para manejar la siguiente señal. Sin embargo, la salida no muestra el casoHacer que los hilos tengan el mismo número de timeslices

#include <pthread.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <iostream> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/time.h> 
#include <signal.h> 
#include <cstdio> 
#include <stdlib.h> 

#define NUM_SENDER_PROCESSES 3 
#define NUM_HANDLER_PROCESSES 4 
#define NUM_SIGNAL_REPORT 10 
#define MAX_SIGNAL_COUNT 100000 


using namespace std; 

volatile int usrsig1_handler_count = 0; 
int usrsig2_handler_count = 0; 
int usrsig1_sender_count = 0; 
int usrsig2_sender_count = 0; 
int monitor_count = 0; 
int usrsig1_monitor_count = 0; 
int usrsig2_monitor_count = 0; 
double time_1[10]; 
double time_2[10]; 
int lock_1 = 0; 
int lock_2 = 0; 
int lock_3 = 0; 
int lock_4 = 0; 
int lock_5 = 0; 


double timestamp() { 
    struct timeval tp; 
    gettimeofday(&tp, NULL); 
    return (double)tp.tv_sec + tp.tv_usec/1000000.; 
} 

void sleepMs(double seconds) { 
    usleep((unsigned int)(seconds*1000000)); 
} 

void *senderfunc(void *parm) { 
    srand(time(0)); 
    while(true) { 
    int signal_id = rand()%2 + 1; 
    if(signal_id == 1) { 
     while(__sync_lock_test_and_set(&lock_3,1) != 0) { 
     } 
     usrsig1_sender_count++; 
     lock_3 = 0; 
     kill(getpid(), SIGUSR1); 
    } else { 
     while(__sync_lock_test_and_set(&lock_4,1) != 0) { 
     } 
     usrsig2_sender_count++; 
     lock_4 = 0; 
     kill(getpid(), SIGUSR2); 
    } 


    int r = rand()%10 + 1; 
    double s = (double)r/100; 
    sleepMs(s); 
    } 
} 

void *handlerfunc(void *parm) 
{ 
    int *index = (int *)parm; 
    sigset_t set; 
    sigemptyset(&set); 
    //cout << (*index) << endl; 
    if((*index) % 2 == 0) { 
    sigaddset(&set, SIGUSR1); 
    } else { 
    sigaddset(&set, SIGUSR2); 
    } 


    int sig; 

    while(true) { 
    sigwait(&set, &sig); 
    //cout << "Handler" << endl; 
    if (sig == SIGUSR1) { 
     while(__sync_lock_test_and_set(&lock_1,1) != 0) { 
     } 
     usrsig1_handler_count++;   
     lock_1 = 0; 
    } else if(sig == SIGUSR2) { 
     while(__sync_lock_test_and_set(&lock_2,1) != 0) { 
     } 
     usrsig2_handler_count++; 
     lock_2 = 0; 
    } 

    sleepMs(0.0001); 
    } 

} 

void *monitorfunc(void *parm) { 

    sigset_t set; 
    sigemptyset(&set); 

    sigaddset(&set, SIGUSR1); 
    sigaddset(&set, SIGUSR2); 

    int sig; 

    while(true) { 
    sigwait(&set, &sig); 
    //cout << "Monitor" << endl; 
    if(sig == SIGUSR1) { 
     time_1[usrsig1_monitor_count] = timestamp(); 
     usrsig1_monitor_count++; 
    } else if(sig == SIGUSR2) { 
     time_2[usrsig2_monitor_count] = timestamp(); 
     usrsig2_monitor_count++; 
    } 
    monitor_count++; 
    //cout << monitor_count << endl; 

    if(monitor_count == NUM_SIGNAL_REPORT) { 
     double difference_1 = 0; 
     double difference_2 = 0; 
     if(usrsig1_monitor_count > 1) { 
     for(int i=0; i<usrsig1_monitor_count-1; i++) { 
      difference_1 = difference_1 + time_1[i+1] - time_1[i]; 
     } 
     cout << "Interval SIGUSR1 = " << difference_1/(usrsig1_monitor_count-1)<< endl; 
     } 

     if(usrsig2_monitor_count > 1) { 
     for(int i=0; i<usrsig2_monitor_count-1; i++) { 
      difference_2 = difference_2 + time_2[i+1] - time_2[i]; 
     } 
     cout << "Interval SIGUSR2 = " << difference_2/(usrsig2_monitor_count-1) << endl; 
     } 
     cout << "Count SIGUSR1 = " << usrsig1_sender_count << endl; 
     cout << "Count SIGUSR2 = " << usrsig2_sender_count << endl; 
     monitor_count = 0; 
     usrsig1_monitor_count = 0; 
     usrsig2_monitor_count = 0; 
    } 

    sleepMs(0.001); 

    } 
} 

int main(int argc, char **argv) 
{ 
    if(argc != 2) { 
    cout << "Required parameters missing. " << endl; 
    cout << "Option 1 = 1 which means run for 30 seconds" << endl; 
    cout << "Option 2 = 2 which means run until 100000 signals" << endl; 
    exit(0); 
    } 

    int option = atoi(argv[1]); 
    int i; 

    pthread_t handlers[NUM_HANDLER_PROCESSES]; 
    pthread_t generators[NUM_SENDER_PROCESSES]; 
    pthread_t monitor; 

    sigset_t set; 
    sigset_t oldset; 
    sigemptyset(&oldset); 
    sigemptyset(&set); 
    sigaddset(&set, SIGUSR1); 
    sigaddset(&set, SIGUSR2); 

    pthread_sigmask(SIG_BLOCK, &set, &oldset); 


    int handler_mask[4] = {0,1,2,3}; 
    //Initializing the handler threads 
    for(i=0; i<NUM_HANDLER_PROCESSES; i++) { 
    pthread_create(&handlers[i], NULL, handlerfunc, (void *)&handler_mask[i]); 
    } 

    pthread_create(&monitor, NULL, monitorfunc, NULL); 

    sleep(5); 

    for(i=0; i<NUM_SENDER_PROCESSES; i++) { 
    pthread_create(&generators[i], NULL, senderfunc, NULL); 
    } 

    if(option == 1) { 
    cout << "Option 1 " << endl; 
    //sleep(30); 
    while(true){ 

    } 
    exit(0); 
    } else { 
    while(true) { 
     if((usrsig1_handler_count + usrsig2_handler_count) >= MAX_SIGNAL_COUNT) { 
     cout << "Count SIGUSR1 = " << usrsig1_handler_count << endl; 
     cout << "Count SIGUSR2 = " << usrsig2_handler_count << endl; 
     exit(0); 
     } else { 
     pthread_yield(); 
     } 
    } 
    } 
} 

Aquí está mi salida

HandlerHandler 

Handler 
Handler 
Monitor 
Monitor 
... whole bunch of Monitor messages 
Monitor 
Monitor 
Handler 
Handler 
... whole bunch of Handler messages 
Handler 
Handler 

Se puede ver la explosión de la pantalla seguido de explosión de manipulador. Sin embargo, en el código una vez que un manejador/monitor maneja una señal y va para sigwait, he agregado una llamada de espera para que el giro pase al siguiente hilo disponible. Sin embargo, esto no está ayudando. Esto debería haberlo hecho uniforme, supongo. Sin embargo, aún el monitor se rompe e imprime. Aunque en el monitor he dormido después de haber terminado su trabajo para una señal

+0

Si desea que la salida se entremezcle, debe usar semáforos o señales. –

+0

@Joachim No lo entendí, ¿a qué te refieres? – user34790

+0

Ver p. ['pthread_cond_init'] (http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_init.html). –

Respuesta

1

OS no tengo idea de que quiera distribuir un TRABAJO entre varios hilos, por lo que OS ejecuta el primer hilo disponible con la más alta prioridad, continúa ejecutándose enhebrar hasta que el hilo actual espere algo (entrada de usuario, actividad de red o disco o ...) u otro subproceso con mayor prioridad esté disponible. - con el fin de aumentar el rendimiento y evitar el cambio de contexto demasiado, el sistema operativo intenta enviar la solicitud en el mismo hilo (frente a su necesidad). Por ejemplo, considere MonitorThread programado para ejecutarse y su llamada al sigwait está satisfecha, ahora hace su acción (mientras que este hilo propio CPU, SO no tiene forma de programar otros hilos) cuando se completa su acción (final de tiempo) llame al sigwait, si hay alguna señal pendiente allí, OS recogerá esa señal y pasará de nuevo a loop, este hilo hará este proceso hasta que no haya más señal pendiente y sigwait bloqueará su operación y la próxima vez se repetirá con otro hilo programado.

Ahora, con el fin de enviar señales por igual, tengo que implementar mi propio mecanismo (ya que el sistema operativo no tiene ningún mecanismo para esto). Puedo crear un condition_variable para cada subproceso y forzar a cada uno de ellos primero a esperar su propio condition_variable y luego llamar al sigwait y después de completar la ejecución establecerá condition_variable del siguiente subproceso y la operación continuará como está !.

3

¿Qué sistema operativo está utilizando? Necesita un sistema operativo en tiempo real (RTOS) para hacerlo de manera confiable. Obtuve buenos resultados utilizando un RTOS muy pequeño llamado On Time RTOS-32 para controlar un controlador de robot. Puede hacer time-slicing con latencia garantizada, o puede elegir hacer una programación cooperativa. Tiene un conjunto de emulación de ventana para un subconjunto de la API de Win. Usamos Visual Studio/VC++ como el IDE. Puede haber una gran variedad de RTOS disponibles ahora. Eso fue hace casi 10 años. Google para RTOS y "sistema operativo en tiempo real".

La alternativa, que puede ser lo suficientemente buena en una máquina rápida y dedicada, es escribir su propio "SO dentro de un sistema operativo" para programar los hilos "a mano". Tendría que cambiar la forma en que los hilos esperan las asignaciones.

Estoy disparando en la oscuridad. ¿Por qué necesita equilibrar la carga entre los hilos? ¿Cuál es la tarea? ¿Cuál es el presupuesto? ¿Tiene que ejecutarse en un hardware particular? En un sistema operativo particular? Si es así, ¿cuál? ¿Qué pasa si va bien? ¿Alguien murmura una mala palabra y se va a almorzar, o una sonda espacial se hunde en el sol?

Cuestiones relacionadas