当前位置: 首页 > 知识库问答 >
问题:

如何在C中的分叉进程上使用POSIX信号量?

李勇
2023-03-14
sem_init(&sem, 1, 1);   /* semaphore*, pshared, value */
.
.
.
if(pid != 0){ /* parent process */
    wait(NULL); /* wait all child processes */

    printf("\nParent: All children have exited.\n");
    .
    .
    /* cleanup semaphores */
    sem_destroy(&sem);      
    exit(0);
}
else{ /* child process */
    sem_wait(&sem);     /* P operation */
    printf("  Child(%d) is in critical section.\n",i);
    sleep(1);
    *p += i%3;  /* increment *p by 0, 1 or 2 based on i */
    printf("  Child(%d) new value of *p=%d.\n",i,*p);
    sem_post(&sem);     /* V operation */
    exit(0);
}
child(0) forked
child(1) forked
  Child(0) is in critical section.
  Child(1) is in critical section.
child(2) forked
  Child(2) is in critical section.
child(3) forked
  Child(3) is in critical section.
child(4) forked
  Child(4) is in critical section.
  Child(0) new value of *p=0.
  Child(1) new value of *p=1.
  Child(2) new value of *p=3.
  Child(3) new value of *p=3.

  Child(4) new value of *p=4.
Parent: All children have exited.

这显然意味着信号量没有正常工作。你能解释一下我应该如何在分叉进程上使用信号量吗?

共有1个答案

栾和玉
2023-03-14

您面临的问题是对sem_init()函数的误解。当您阅读手册页面时,您将看到以下内容:

pshared参数指示此信号量是在进程的线程之间共享,还是在进程之间共享。

如果您读到这一点,您会认为pshared的非零值将使信号量成为进程间信号量。然而,这是错误的。您应该继续阅读,您将了解必须在共享内存区域中定位信号量。要做到这一点,可以使用如下所示的几个函数:

    null
#include <stdio.h>          /* printf()                 */
#include <stdlib.h>         /* exit(), malloc(), free() */
#include <sys/types.h>      /* key_t, sem_t, pid_t      */
#include <sys/shm.h>        /* shmat(), IPC_RMID        */
#include <errno.h>          /* errno, ECHILD            */
#include <semaphore.h>      /* sem_open(), sem_destroy(), sem_wait().. */
#include <fcntl.h>          /* O_CREAT, O_EXEC          */


int main (int argc, char **argv){
    int i;                        /*      loop variables          */
    key_t shmkey;                 /*      shared memory key       */
    int shmid;                    /*      shared memory id        */
    sem_t *sem;                   /*      synch semaphore         *//*shared */
    pid_t pid;                    /*      fork pid                */
    int *p;                       /*      shared variable         *//*shared */
    unsigned int n;               /*      fork count              */
    unsigned int value;           /*      semaphore value         */

    /* initialize a shared variable in shared memory */
    shmkey = ftok ("/dev/null", 5);       /* valid directory name and a number */
    printf ("shmkey for p = %d\n", shmkey);
    shmid = shmget (shmkey, sizeof (int), 0644 | IPC_CREAT);
    if (shmid < 0){                           /* shared memory error check */
        perror ("shmget\n");
        exit (1);
    }

    p = (int *) shmat (shmid, NULL, 0);   /* attach p to shared memory */
    *p = 0;
    printf ("p=%d is allocated in shared memory.\n\n", *p);

    /********************************************************/

    printf ("How many children do you want to fork?\n");
    printf ("Fork count: ");
    scanf ("%u", &n);

    printf ("What do you want the semaphore value to be?\n");
    printf ("Semaphore value: ");
    scanf ("%u", &value);

    /* initialize semaphores for shared processes */
    sem = sem_open ("pSem", O_CREAT | O_EXCL, 0644, value); 
    /* name of semaphore is "pSem", semaphore is reached using this name */

    printf ("semaphores initialized.\n\n");


    /* fork child processes */
    for (i = 0; i < n; i++){
        pid = fork ();
        if (pid < 0) {
        /* check for error      */
            sem_unlink ("pSem");   
            sem_close(sem);  
            /* unlink prevents the semaphore existing forever */
            /* if a crash occurs during the execution         */
            printf ("Fork error.\n");
        }
        else if (pid == 0)
            break;                  /* child processes */
    }


    /******************************************************/
    /******************   PARENT PROCESS   ****************/
    /******************************************************/
    if (pid != 0){
        /* wait for all children to exit */
        while (pid = waitpid (-1, NULL, 0)){
            if (errno == ECHILD)
                break;
        }

        printf ("\nParent: All children have exited.\n");

        /* shared memory detach */
        shmdt (p);
        shmctl (shmid, IPC_RMID, 0);

        /* cleanup semaphores */
        sem_unlink ("pSem");   
        sem_close(sem);  
        /* unlink prevents the semaphore existing forever */
        /* if a crash occurs during the execution         */
        exit (0);
    }

    /******************************************************/
    /******************   CHILD PROCESS   *****************/
    /******************************************************/
    else{
        sem_wait (sem);           /* P operation */
        printf ("  Child(%d) is in critical section.\n", i);
        sleep (1);
        *p += i % 3;              /* increment *p by 0, 1 or 2 based on i */
        printf ("  Child(%d) new value of *p=%d.\n", i, *p);
        sem_post (sem);           /* V operation */
        exit (0);
    }
}

输出

./a.out 
shmkey for p = 84214791
p=0 is allocated in shared memory.

How many children do you want to fork?
Fork count: 6 
What do you want the semaphore value to be?
Semaphore value: 2
semaphores initialized.

  Child(0) is in critical section.
  Child(1) is in critical section.
  Child(0) new value of *p=0.
  Child(1) new value of *p=1.
  Child(2) is in critical section.
  Child(3) is in critical section.
  Child(2) new value of *p=3.
  Child(3) new value of *p=3.
  Child(4) is in critical section.
  Child(5) is in critical section.
  Child(4) new value of *p=4.
  Child(5) new value of *p=6.

Parent: All children have exited.

检查shmkey是不错的,因为当ftok()失败时,它返回-1。但是,如果您有多个共享变量,并且ftok()函数多次失败,则具有shmkey-1的共享变量将驻留在共享内存的同一区域中,导致其中一个变量的更改影响另一个变量。因此程序的执行会变得混乱。为了避免这种情况,最好检查ftok()是否返回-1(最好签入源代码,而不是像我那样打印到屏幕上,尽管我希望向您显示键值,以防发生冲突)。

注意信号量是如何声明和初始化的。这与您在问题中所做的不同(sem_tsemvssem_t*sem)。而且,您应该按照它们在本示例中的样子使用它们。不能定义sem_t*并在sem_init()中使用它。

 类似资料:
  • 问题内容: 我想派生多个进程,然后在它们上使用一个信号灯。这是我尝试过的: 输出为: 显然,这意味着信号灯没有按预期的方式工作。您能解释一下我应该如何在分支进程中使用信号量? 问题答案: 您面临的问题是对功能的误解。阅读手册页时, 您将看到以下内容: pshared参数指示此信号量是在进程的线程之间还是在进程之间共享。 如果您到此为止都读完了,您将认为pshared的非零值将使信号量成为进程间信号

  • 问题内容: 假设我创建了一个信号量。如果我派生了一堆子进程,它们还会使用相同的信号量吗? 另外,假设我创建了一个内部带有信号灯并分叉的结构。所有子进程仍然使用相同的信号量吗?如果不是,将struct + semaphores存储在共享内存中是否允许子进程使用相同的信号量? 我对派生的子进程如何使用相同的信号量感到非常困惑。 问题答案: 假设我创建了一个信号量。如果我派生了一堆子进程,它们还会使用相

  • 我有多个进程与Sempahore同步。我知道这段代码不允许gurantee出现这样的情况:在sem_getvalue期间,即使值变为零,甚至在调用特定进程中的sem_post之前,anotehr进程也可能调用sem_post,使值变为2。如何解决这种情况。 我的问题不能通过互斥体来解决,在我的问题中,有些进程只用于信号,即操作,而在互斥体中,所有进程都将等待并不断地发出信号

  • 这个问题要求使用两个信号量,一个作为互斥量,一个作为计数信号量,并使用这两个信号量来模拟学生和教师助手之间的交互。 我已经能够很容易地使用二进制信号量,但是我似乎找不到很多例子来说明计数信号量的使用,所以我很确定我错了,这导致我的代码不能正确执行。 我的代码如下 我的主要问题是:如何让线程同时轮询计数信号量? 我正试图获得备份,一些学生被迫离开(或退出线程),而其他人则在信号量中等待。任何帮助都是

  • 我只能在线程之间使用它,但我想在进程之间共享。所以我的问题是,如何使用posix计数信号量来制作二进制信号量?