【问题标题】:Synchronizing two child processes with semaphores in c在c中使用信号量同步两个子进程
【发布时间】:2026-01-21 09:45:01
【问题描述】:

我必须创建一个程序来同步两个进程,每个进程只打印一个字母,这样每当我们观察程序的输出时,"A""B" 的数量之间的差异不大于 2。

所以这会被接受:

BAABBAABBABA

这不会是因为它打印了 4 个 B 而只打印了 2 个 A:

ABBABB

所以对于初学者,我决定使用 POSIX 信号量。 我创建了两个信号量,使用 sem_open 为它们提供所有权限 然后我创建了两个子进程,对于每个子进程,我打开我创建的信号量,如sem_open 的手册页中所述并对其进行操作。

我认为这不是 sem_postsem_wait 的逻辑问题,因为程序似乎忽略了它们。

所以我的问题是。出了什么问题?

编辑:我真的不需要解决问题的方法。仅一些指导将不胜感激并欢迎作为答案。提前谢谢!

#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>

int main(void){



  sem_t *semA = sem_open("/semA", O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 0);   //Initialize semaphore(= 0) for process A
  sem_t *semB = sem_open("/semB", O_CREAT|O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 0);   //Initialize semaphore(= 0) for process B


  if (fork()){      // parent process
    if(fork()){}
    else{
      sem_t *childsemA = sem_open("/semA", 0);
      sem_t *childsemB = sem_open("/semB", 0);
      while(1){
        printf("A");
        sem_post(childsemB);
        sem_wait(childsemA);
      }
    }
  }
  else{
    sem_t *childsemA = sem_open("/semA", 0);
    sem_t *childsemB = sem_open("/semB", 0);
    while(1){
      printf("B");    // child2 process
      sem_post(childsemA);
      sem_wait(childsemB);
    }
  }

  return 0;
}

输出:

【问题讨论】:

  • 如果我没记错的话,信号量旨在与线程(轻量级进程)一起使用,而不是与进程一起使用。 fork 创建一个不共享父级内存的进程,所以我认为您父级的信号量与您孩子的信号量没有交互。
  • @mmeisson:不,OP 正在使用sem_open() 打开命名信号量;这些在进程之间共享。
  • OP,标准 C 库缓冲标准输出。在每个 printf() 之后添加 fflush(stdout); 以使 C 库将字母发送到实际的标准输出。
  • 你不需要childsemAchildsemB,只需要使用父级打开的semAsemB即可。
  • 对于奋斗者,不要让您的系统陷入困境,请在父母中使用wait(0); 电话

标签: c process synchronization fork semaphore


【解决方案1】:

我可以建议您使用 System V 信号量吗?这是代码:

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

#include "Semaphores.h"

#define SEM1_KEY (key_t)888
#define SEM2_KEY (key_t)1234

int sem1, sem2;


int main()
{
    pid_t pid;

    sem1 = semget(SEM1_KEY, 1, IPC_CREAT | 0666);
    if(sem1 < 0)
    {
        fprintf(stderr, "\nSEMGET Failed\n");
        exit(EXIT_FAILURE);
    }

    sem2 = semget(SEM2_KEY, 1, IPC_CREAT | 0666);
    if(sem1 < 0)
    {
        fprintf(stderr, "\nSEMGET Failed\n");
        exit(EXIT_FAILURE);
    }

    SEM_SET(sem1, 1);
    SEM_SET(sem2, 0);

    if((pid = fork()) == -1)
    {
        fprintf(stderr, "\nError in fork()\n");
        exit(EXIT_FAILURE);
    }
    if(pid == 0)
    {
        while(1)
        {   
            SEM_WAIT(sem2);
            printf("%c", 'B');
            fflush(stdout);
            sleep(1);
            SEM_POST(sem1);
        }
    }

    while(1)
    {
        SEM_WAIT(sem1);
        printf("%c", 'A');
        fflush(stdout);
        sleep(1);
        SEM_POST(sem2);
    }

    wait(0);

    SEM_DEL(sem1);
    SEM_DEL(sem2);
    exit(EXIT_SUCCESS);
}

这是包含 System V 信号量实现的头文件 Semaphores.h:

#include <sys/sem.h>


union semun
{
    int val;

    struct semid_ds * buf;

    unsigned short * array;

};


int SEM_SET(int sem_id, int sem_val)
{
    union semun sem_union;

    sem_union.val = sem_val;

    return semctl(sem_id, 0, SETVAL, sem_union);
}

int SEM_DEL(int sem_id)
{
    return semctl(sem_id, 0, IPC_RMID);
}

int SEM_WAIT(int sem_id)
{
    struct sembuf sem_buf;

    sem_buf.sem_num = 0;
    sem_buf.sem_op = -1;
    sem_buf.sem_flg = SEM_UNDO;
    return semop(sem_id, &sem_buf, 1);
}

int SEM_POST(int sem_id)
{
    struct sembuf sem_buf;

    sem_buf.sem_num = 0;
    sem_buf.sem_op = 1;
    sem_buf.sem_flg = SEM_UNDO;
    return semop(sem_id, &sem_buf, 1);
}

结果会是这样的:

ABABABABABABABA等

fflush() 可能是问题所在,但是您的代码有一些泄漏,您需要了解什么是临界区,并且您需要检查 fork() 的返回值。

【讨论】:

  • 我赞成这个,因为它是一个很好的答案,但它并不能完全解决我原来的问题。你强迫AB 来回切换,而我希望代码允许一个字母根据竞争条件连续出现两次。