2012-05-05 10 views
5

La pregunta: ¿Es posible garantizar que la ejecución de código solo puede ocurrir en un subproceso a la vez en un programa multiproceso? (O algo que se aproxima a esto)Ejecución de código serie en un programa multiproceso en C++

Específicamente: Tengo un controlador M (que es un hilo) y los hilos A, B, C. Me gustaría que M pueda decidir a quién se le debe permitir ejecutar. Cuando el hilo ha finalizado (ya sea finalmente o temporalmente) el control se transfiere a M.

Por qué: Lo ideal es que A, B y C ejecuten su código en su propio subproceso mientras que los otros no se están ejecutando. Esto permitiría que cada subproceso mantuviera su puntero de instrucción y la pila mientras se pausan, comenzando desde donde lo dejaron cuando el controlador les devuelve el control.

Lo que estoy haciendo ahora: He escrito un código que realmente puede hacer esto, pero no me gusta.

En pseudo-C:

//Controller M 
//do some stuff 
UnlockMutex(mutex); 
do{}while(lockval==0); 
LockMutex(mutex); 
//continue with other stuff 


//Thread A 
//The controller currently has the mutex - will release it at UnlockMutex 
LockMutex(mutex); 
lockval=1; 
//do stuff 
UnlockMutex(mutex); 

La razón por qué se requiere

do{}while(lockval==0); 

es que cuando se desbloquea el mutex, ambos A y M continuarán. Este truco asegura que A no desbloqueará el mutex antes de que M pueda volver a bloquearlo, lo que permite a A retomar el bloqueo por segunda vez y ejecutarlo nuevamente (solo debería ejecutarse una vez).

El do-while parece exagerado, pero cumple su función. Entonces mi pregunta es, ¿hay una mejor manera?

+0

¿Por qué no desea que los subprocesos A, B y C se ejecuten al mismo tiempo? ¿Cuál es el problema que estás tratando de resolver? Es casi seguro que hay una forma mejor de resolver el problema, pero debe decirnos cuál es el problema * *. –

+0

Esta parte me confunde: "Esto permitiría que cada subproceso mantenga su puntero de instrucción y la pila mientras hacen una pausa". Ese no es el propósito de los mutexes.El sistema operativo (asumiendo el modelo de subproceso preventivo) mantiene la pila de cada subproceso y se registra a medida que les da tiempo de CPU. – veefu

+1

@veefu - OP quiere 'hilos verdes', fibras AKA, (creo). A, B y C todos obtienen su propia pila, pero solo uno puede ejecutarse a la vez porque solo hay un hilo del kernel. –

Respuesta

2

Suponiendo que se ejecuta en Windows, puede intentar mirar Fibras. (Consulte, por ejemplo, http://developer.amd.com/Pages/1031200677.aspx o simplemente google "windows fibers".)

Sospecho que realmente está buscando coroutines.

+0

Sí - suena como el usuario 'hilos' fibras AKA. –

+0

Esto suena exactamente a lo que necesito. ¡Gracias! – EggplantBonanza

+1

Si los hilos A, B y C vuelven todos al hilo M del controlador de todos modos, ¿por qué no acaba con todos los hilos y simplemente llama a funcA fucnB y funcC desde el hilo M? ¿La abstracción de la fibra es realmente necesaria? – veefu

0

Supongo que estás codificando C++ en Linux y usando pthread API. Aquí está el código, no tan robusto, pero es un buen punto para comenzar. Espero que sea útil para ti Usando "g ++ test_controller_thread.cpp -pthread -o test_controller_thread" para hacer el ejecutivo binario.

// 3 threads, one for controller, the other two for worker1 and worker2. 
// Only one thread can proceed at any time. 
// We use one pthread_mutex_t and two pthread_cond_t to guarantee this. 
#include <pthread.h> 
#include <unistd.h> 
#include <stdio.h> 

static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 
static pthread_cond_t g_controller_cond = PTHREAD_COND_INITIALIZER; 
static pthread_cond_t g_worker_cond = PTHREAD_COND_INITIALIZER; 

void* controller_func(void *arg) { 
    printf("entering the controller thread. \n"); 
    // limit the max time the controller can run 
    int max_run_time = 5; 
    int run_time = 0; 
    pthread_mutex_lock(&g_mutex); 
    while (run_time++ < max_run_time) { 
     printf("controller is waitting.\n"); 
     pthread_cond_wait(&g_controller_cond, &g_mutex); 
     printf("controller is woken up.\n"); 
     pthread_cond_signal(&g_worker_cond); 
     printf("signal worker to wake up.\n"); 
    } 
    pthread_mutex_unlock(&g_mutex); 
} 

void* worker_func(void *arg) { 
    int work_id = *(int*)arg; 
    printf("worker %d start.\n", work_id); 
    pthread_mutex_lock(&g_mutex); 
    while (1) { 
     printf("worker %d is waitting for controller.\n", work_id); 
     pthread_cond_wait(&g_worker_cond, &g_mutex); 
     printf("worker %d is working.\n", work_id); 
     pthread_cond_signal(&g_controller_cond); 
     printf("worker %d signal the controller.\n", work_id); 
    } 
    pthread_mutex_unlock(&g_mutex); 
} 

int main() { 
    pthread_t controller_thread, worker_thread_1, worker_thread_2; 
    int worker_id_1 = 1; 
    int worker_id_2 = 2; 
    pthread_create(&controller_thread, NULL, controller_func, NULL); 
    pthread_create(&worker_thread_1, NULL, worker_func, &worker_id_1); 
    pthread_create(&worker_thread_2, NULL, worker_func, &worker_id_2); 

    sleep(1); 
    printf("\nsignal the controller to start all the process.\n\n"); 
    pthread_cond_signal(&g_controller_cond); 

    pthread_join(controller_thread, NULL); 
    pthread_cancel(worker_thread_1); 
    pthread_cancel(worker_thread_2); 

    return 0; 
} 
Cuestiones relacionadas