为什么信号量不工作?

why is the semaphore not working?

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

结果应该是:

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

程序退出,但它从不向信号量发送信号。

XY Problem?

如果你想做的是等待你的子进程完成,你不需要信号量,但是waitwaitpid。以下 C 代码具有您预期的输出。

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

注意:我用 C 语言做了,因为您使用的唯一 C++ 是 for 循环中的初始声明并使用 cout << "blah" << endl;

打印

来自 sem_init 的联机帮助页:

If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)). (Since a child created by fork(2) inherits its parent's memory mappings, it can also access the semaphore.) Any process that can access the shared memory region can operate on the semaphore using sem_post(3), sem_wait(3), etc.

POSIX 信号量是栈上结构。它们不像文件描述符那样是对内核维护结构的引用计数引用。如果你想与两个进程共享一个POSIX信号量,你需要自己处理共享部分。

这应该有效:

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

注意: 如果您只需要这种行为,那么 waitpid 显然是可行的方法。我假设你想要的是测试 POSIX 信号量。

不使用 sem_init(),而是使用 sem_open()。这是因为信号量需要位于共享地址 space 中,而不是位于通过 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);
...

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