Why does the semaphore not work?

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

the result should be:

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

The program exits, but instead it does not signal a semaphore.

+5
source share
3 answers

From sem_init manpage:

If pshared is nonzero, then the semaphore is split between the processes and should be located in the shared memory area (see shm_open (3), mmap (2) and shmget (2)). (Since the child created by fork (2) inherits its parent memory mappings, it can also access the semaphore.) Any process that can access the shared memory area can work on the semaphore using sem_post (3), sem_wait (3), and so on. .d.

POSIX semaphores are structures on the stack. They do not reference kernel-supported structures such as filedescriptors. If you want to share the POSIX semaphore with two processes, you need to take care of partial separation yourself.

This should work:

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

Note. . If you want only this behavior, then waitpid is obviously the way to go. I assume you want to test POSIX semaphores.

+7
source

XY problem?

If what you want to do is wait for the completion of your child process, you do not need semaphores, but wait or waitpid . The following C code has the expected result.

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

NOTE. I did this in C because the only C ++ you used was the initial declaration in the for loop and printed using cout << "blah" << endl;

+4
source

Instead of sem_init() use sem_open() . This is due to the fact that the semaphore must be in the general address space, and not in the process stack, where it is duplicated via 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); ... 

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

+1
source

Source: https://habr.com/ru/post/1235599/


All Articles