2010-11-27 15 views
5

Estoy pirateando una asignación uni y he encontrado un problema con mi código que se supone que engendra 2 procesos, donde el segundo proceso espera que el primero se complete antes de la ejecución. Esto es lo que tengo hasta ahora:¿Por qué mi mutex no funciona correctamente en una aplicación C multiproceso?

sem_t mutex; 
int producer; int consumer; 
sem_init(&mutex, 0, 1); 
producer = fork(); 
consumer = fork(); 

if (producer == 0) { 
    if (VERBOSE) printf("Running producer\n"); 
    /* down semaphore */ 
    sem_wait(&mutex); 
    /* START CRITICAL REGION */ 
    get_files(N); 
    /* END CRITICAL REGION */ 
    /* up semaphore */ 
    sem_post(&mutex); 
    if (VERBOSE) printf("Ending producer\n"); 
    exit(0); 
} 

if (consumer == 0) { 
    if (VERBOSE) printf("Running consumer\n"); 
    /* down semaphore */ 
    sem_wait(&mutex); 
    /* START CRITICAL REGION */ 
    /* do stuff */ 
    /* END CRITICAL REGION */ 
    /* up semaphore */ 
    sem_post(&mutex); 
    if (VERBOSE) printf("Ending consumer\n"); 
    exit(0); 
} 
/* parent waits for both to complete */ 
wait(NULL); 

Ahora, sé que en el "mundo real" esto es realmente estúpida. Si mi 'consumidor' no hace nada hasta que mi 'productor' haya terminado, entonces bien podría no tener 2 procesos como este, pero la tarea es tratar de ilustrar una condición de carrera, por lo que nos han dicho específicamente hacerlo de esta forma.

Entonces, mi problema es que el proceso del consumidor no está esperando al productor. Supuse que como el semáforo se eliminó en el productor (sem_wait(&mutex);), entonces no estaría disponible para el consumidor hasta que se llame al sem_post(&mutex); en el productor.

Además, lo mejor que puedo decir es que la línea wait(NULL); no está esperando que se completen ambos procesos.

¿He malinterpretado algo críticamente?

+2

Bien pedido y bien etiquetado. – sje397

+0

Crea procesos NO hilos. – tur1ng

+0

tenedor comparte memoria ... debería ver y ser capaz de usar los mutexes del mismo modo no? (Puedo estar bien aquí, no lo he intentado) – tobyodavies

Respuesta

4

Simplemente porque fork el hilo productor primero no significa que el sistema operativo lo programará para ejecutarse primero, es bastante posible que el consumidor realmente se ejecute y obtenga el bloqueo primero.

Además, debe verificar el valor de retorno de sem_wait - es posible regresar sin sostener el semáforo.

También es muy posible (ya que varias personas han notado en los comentarios) que los semáforos pueden simplemente no trabajar a través de fork ed procesos

EDITAR - si se pasa un valor distinto de cero para el argumento 2 de sem_init(sem_t *sem, int pshared, unsigned value) al inicializar POSIX semáforos se procesos de trabajo a través de

EDITAR - Ver here para una explicación mucho mejor de lo que podría dar, completa con código fuente para hacer casi exactamente lo que quiere

+0

Bien, investigué su sugerencia, y parece que NI se están otorgando bloqueos de semáforo. Ambas líneas 'sem_wait (& mutex);' devuelven un valor de -1 que Google me dice que significa un error. ¿Qué debería hacer ahora? (P.S. Supongo que es por eso que mi 'wait (NULL);' tampoco funciona, ¿eh? – Ash

+0

Sí, el punto es que debes llamar a sem_init y verificar el estado de sem_wait. –

+0

debe hacer 'while (sem_wait (mutex)! = 0);' como una sugerencia más simple (observe el ';' - ciclo sin hacer nada) – tobyodavies

1

¿Ha pr ¿Has proporcionado el código completo en la pregunta?

Si es así, falta la inicialización del semáforo. Debe llamar al sem_init o al sem_open antes de usar el semáforo.

Lee here.

EDIT Usted está especificando pshared = 0 en la llamada sem_init. Esto hace que el proceso del semáforo sea local (es decir, se puede usar solo para sincronizar subprocesos de un proceso). fork crea un proceso hijo, por lo que el semáforo no hace nada útil.

If pshared has value 0, then the semaphore is shared between the threads of a process. If pshared is non-zero, then the semaphore is shared between processes.

(la cita es desde el enlace anterior)

+0

Lo era, pero edité la pregunta para incluirla. – Ash

10

Debe tener comprobación de errores en sus llamadas de semáforo. Use perror() para mostrar el error si sem_wait(), sem_init() o sem_post() devuelve un valor distinto de cero.

En segundo lugar, crea más procesos de los que cree. Su primer fork() resultados en un padre (con producer distinto de cero) y un hijo (con producer cero). Ambos procesos ejecutan el segundo fork(), por lo que ahora tiene cuatro procesos.

En tercer lugar, la variable sem_t debe compartirse entre los procesos, por lo que debe almacenarse en una región de memoria compartida. La forma más sencilla de lograr esto es con mmap():

sem_t *sem = mmap(NULL, sizeof *sem, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 

(Ejecutar que antes de la sem_init() y la primera fork()).

En el momento, no se define qué proceso se ejecutará primero, por lo que no puede confiar en el hilo del productor llamando al sem_wait() antes que el consumidor. En cambio, inicialice el semáforo en cero con sem_init(), y solo llame al sem_wait() en el consumidor: esto bloqueará al consumidor. El productor se ejecuta y llama al sem_post() cuando está listo, lo que permite que el consumidor proceda.

La llamada sem_init() debe especificar pshared son distintos de cero y value como 0, por lo que debe ser similar:

if (sem_init(sem, 1, 0) != 0) { 
    perror("sem_init"); 
    exit(1); 
} 

En quinto lugar, wait(NULL) sólo espera para un solo proceso hijo para salir. Llámalo dos veces para esperar dos procesos secundarios.

+0

Has visto el error # 2, así que gracias por eso. La pregunta fue modificada para actualizarlo sobre los otros elementos de su respuesta. Sin embargo, mientras está en lo correcto, en esta situación, no creo que ese sea el problema. – Ash

+0

de acuerdo con O'Reily (http://linuxdevcenter.com/pub/a/linux/2007/05/24/semaphores-in-linux.html?page=5) solo necesita compartir la memoria si los procesos no son parentales/child – tobyodavies

+0

'sem_wait' simplemente bloqueará y nunca tendrá éxito en un semáforo con un valor inicial de 0 no? Es posible que haya leído mal la página de manual, pero mi entendimiento es que el valor de un semáforo representa el número de 'usuarios' adicionales que puede manejar de modo que un semáforo con valor = 1 es equivalente a un mutex ... – tobyodavies

0

Antes que nada, no creo que los mutexes funcionen con procesos. La razón es que los procesos bifurcados no comparten memoria. Podrán leer la misma memoria que antes de la horquilla, pero cada vez que uno de ellos escriba en la memoria, el nuevo proceso recibirá su propia copia.

En segundo lugar, puede que tenga que inicializar sus mutexes, o el uso de ellos podría no estar definido.

Cuestiones relacionadas