2015-11-10 32 views
5
#include <stdio.h> 
#include <sys/types.h> 
#include <iostream> 
#include <unistd.h> 
#include <fstream> 
#include <string> 
#include <semaphore.h> 

using namespace std; 

int main(int argc, char *argv[]){ 
    int pshared = 1; 
    unsigned int value = 0; 
    sem_t sem_name; 
    sem_init(&sem_name, pshared, value); 

    int parentpid = getpid(); 
    pid_t pid = fork(); 

    if (parentpid == getpid()){ 
    cout << "parent id= " << getpid() << endl; 
    sem_wait(&sem_name); 
    cout << "child is done." << endl; 
    } 

    if (parentpid != getpid()){ 
    cout << "child id= " << getpid() << endl; 
    for (int i = 0; i < 10; i++) 
     cout << i << endl; 

    sem_post(&sem_name); 
} 
    sleep(4); 
    return 0; 
} 

il risultato dovrebbe essere:perché il semaforo non funziona?

parent id 123456. 
child id 123457. 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
child is done. 

uscite del programma, ma invece non è mai segnala il semaforo.

+0

Benvenuto U & L! abbiamo il tuo codice e quale dovrebbe essere il risultato ... qual è il risultato effettivo? come sei sicuro che il semaforo non sia mai segnalato? potresti modificare la tua domanda per aggiungerla. Finora non trovo nulla di sbagliato nel tuo codice –

risposta

7

Dalla pagina di manuale sem_init s':

Se pshared è diverso da zero, quindi il semaforo è condiviso tra i processi e dovrebbe trovarsi in una regione di memoria condivisa (vedere shm_open (3), mmap (2) e shmget (2)). (Poiché un figlio creato dalla forcella (2) eredita i mapping della memoria del genitore, può anche accedere al semaforo.) Qualsiasi processo che possa accedere a area di memoria condivisa può operare sul semaforo utilizzando sem_post (3), sem_wait (3) , ecc.

I semafori POSIX sono strutture in pila. Non sono riferimenti conteggiati di riferimento a una struttura gestita dal kernel come sono gli autori di file. Se si desidera condividere un semaforo POSIX con due processi, è necessario occuparsi personalmente della parte di condivisione.

Questo dovrebbe funzionare:

#include <fstream> 
#include <iostream> 
#include <semaphore.h> 
#include <stdio.h> 
#include <string> 
#include <sysexits.h> 
#include <sys/mman.h> 
#include <sys/types.h> 
#include <unistd.h> 


int main(int argc, char *argv[]){ 
    using namespace std; 
    sem_t* semp = (sem_t*)mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, 0, 0); 
    if ((void*)semp == MAP_FAILED) { perror("mmap"); exit(EX_OSERR); } 

    sem_init(semp, 1 /*shared*/, 0 /*value*/); 

    pid_t pid = fork(); 
    if(pid < 0) { perror("fork"); exit(EX_OSERR); } 

    if (pid==0){ //parent 
    cout << "parent id= " << getpid() << endl; 
    sem_wait(semp); 
    cout << "child is done." << endl; 
    }else { //child 
    cout << "child id= " << getpid() << endl; 
    for (int i = 0; i < 10; i++) 
     cout << i << endl; 
    sem_post(semp); 
    } 
    return 0; 
} 

Nota: Se si desidera solo questo comportamento, quindi waitpid è ovviamente la strada da percorrere. Suppongo che quello che vuoi sia provare i semafori POSIX.

+0

Un bambino biforcuto ha bisogno di un'area di memoria condivisa con il genitore per poter accedere al semaforo? È sufficiente ad es. dichiarare il semaforo come variabile globale nel codice condiviso? Ho trovato la frase tra parentesi confuse quando l'ho letta. –

+0

@dave_alcarin Sì + no. Ho aggiunto qualche codice di esempio. – PSkocik

+0

Quindi, è necessaria una memoria condivisa, ma prendo atto di ciò che la pagina man ha detto è che la mappatura (da mmap) è ereditata. Bel esempio! +1 –

4

XY Problem?

Se ciò che si vuole fare è quello di attendere che il processo figlio da fare, non hai bisogno di semafori, ma wait o waitpid. Il seguente codice C ha l'output atteso.

#include <stdio.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/wait.h> 

int main(void){ 
    pid_t pid; 
    pid = fork(); 
    if (pid < 0) { 
     fprintf(stderr, "fork failed!\n"); 
     return 1; 
    } 
    if (pid == 0) { 
     int i; 
     printf("child id= %d\n", getpid()); 
     for (i = 0; i < 10; i++) { 
      printf("%d\n",i); 
     } 
    } 
    else { 
     int status; 
     printf("parent id= %d\n", getpid()); 
     waitpid(-1, &status, 0); 
     printf("child is done\n"); 
    } 
    return 0; 
} 

NOTA: L'ho fatto in C, perché l'unica C++ che si stava utilizzando era dichiarazione iniziale in un ciclo for e stampe con cout << "blah" << endl;

1

Invece di utilizzare sem_init(), utilizzare sem_open(). Questo perché il semaforo deve essere nello spazio di indirizzamento condiviso piuttosto che nello stack del processo in cui viene duplicato tramite lo fork().

#include <fcntl.h> 
... 

sem_t *sem_ptr; 
sem_ptr = sem_open("my_semaphore", O_CREAT, 0644, value); 
... 

sem_wait(sem_ptr); 
... 

sem_post(sem_ptr); 
... 

Tratto da http://blog.superpat.com/2010/07/14/semaphores-on-linux-sem_init-vs-sem_open/