2015-11-10 38 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; 
} 

wynik powinien być:dlaczego semafor nie działa?

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

wyjścia programu, lecz nigdy nie sygnalizuje semafora.

+0

Witamy U & L! mamy twój kod i jaki powinien być wynik ... jaki jest rzeczywisty wynik? jak się masz pewność, że semafor nigdy nie jest sygnalizowany? czy możesz edytować swoje pytanie, aby je dodać. Do tej pory nie wydaje mi się, aby znaleźć coś złego w kodzie –

Odpowiedz

7

Od sem_init „s podręcznika:

Jeśli pshared jest niezerowy, wtedy semafor jest dzielony pomiędzy procesy i powinien znajdować się w regionie pamięci współdzielonej (zobacz shm_open (3), mmap (2) i shmget (2)). (Ponieważ potomek utworzony przez fork (2) dziedziczy mapowania pamięci rodzica, może również uzyskać dostęp do semafora.) Każdy proces, który może uzyskać dostęp do , region pamięci współużytkowanej może działać na semaforze za pomocą sem_post (3), sem_wait (3) itp.

Semafory POSIX są strukturami stosowanymi na stosie. Nie są to odnośniki odwoływane do referencji do struktury obsługiwanej przez jądro, takie jak pliki z nazwami plików. Jeśli chcesz współdzielić semafor POSIX z dwoma procesami, sam musisz zadbać o sam dzielenie się.

To powinno działać:

#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; 
} 

Uwaga: Jeśli chcesz tylko ten problem, następnie waitpid jest oczywiście do zrobienia. Zakładam, że chcesz przetestować semafory POSIX.

+0

Czy rozwidlone dziecko potrzebuje wspólnego obszaru pamięci z rodzica, aby uzyskać dostęp do semafora? Czy to wystarczy? zadeklarować semafor jako zmienną globalną we wspólnym kodzie? Znalazłem zdanie pomiędzy nawiasami, mylące, gdy je czytałem. –

+0

@dave_alcarin Tak + nie. Dodałem przykładowy kod. – PSkocik

+0

Tak więc pamięć współdzielona jest rzeczywiście potrzebna, ale przyjmuję, że strona man mówi, że mapowanie (z mmap) jest dziedziczone. Dobry przykład! +1 –

4

XY Problem?

Jeśli to, co chcesz zrobić, to czekać na proces dziecko do zrobienia, nie trzeba semaforów, ale wait lub waitpid. Poniższy kod C ma oczekiwane wyniki.

#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; 
} 

UWAGA: Zrobiłem w C, ponieważ tylko C++ uzywasz był wstępną deklarację w for pętli i wydruki z cout << "blah" << endl;

1

Zamiast używać sem_init(), użyj sem_open(). Dzieje się tak dlatego, że semafor musi znajdować się we wspólnej przestrzeni adresowej, a nie na stosie procesu, gdzie jest duplikowany poprzez 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); 
... 

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