在多个进程之间共享POSIX信号量 [英] Share POSIX semaphore among multiple processes

查看:73
本文介绍了在多个进程之间共享POSIX信号量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建两个子进程,每个子进程都会调用execvp进行分叉,并且可执行文件之间共享POSIX信号.

I need to create two child processes each of which calls execvp ater being forked, and the executables share POSIX semaphores between them.

我需要创建共享内存还是只实现命名信号量?

Do I need to create a shared memory or just implement named semaphores?

我从以下链接中得到了两个答案:

I got two answers from the following links:

  1. 分叉的子进程是否使用相同的信号量?
  2. 如何使用共享内存在进程之间共享信号量
  1. Do forked child processes use the same semaphore?
  2. How to share semaphores between processes using shared memory

但是我对如何进行实施感到困惑.

But I am confused about how to proceed in the implementation.

推荐答案

我需要创建共享内存还是只实现命名 信号量?

Do I need to create a shared memory or just implement named semaphores?

这两种方法都行得通.选择一个并继续使用-尽管我个人更喜欢命名信号量,因为您不必处理内存分配和设置共享内存段.我认为,用于创建和使用命名信号量的界面更加友好.

Either approach will work. Pick one and go with it - though I personally prefer named semaphores because you don't have to deal with memory allocation and with setting up the shared memory segments. The interface for creating and using named semaphores is way more friendly, in my opinion.

在您的示例场景中,使用命名信号量,会发生以下情况:

With named semaphores, in your example scenario, here's what happens:

  • 您可以使用sem_open(3)在父进程中创建并初始化信号量.给它一个子进程将要知道的众所周知的名字.此名称用于在系统中查找信号灯.
  • 关闭父级中的信号量,因为它不会使用它.
  • 分叉并执行
  • 取消信号灯与sem_unlink(3)的链接.必须只做一次.其实并不重要(在任何引用信号量对象的进程都可以做到这一点).可以在其他进程仍将其打开的情况下取消链接的链接:只有在所有其他进程都将其关闭后才能销毁该信号,但是请记住,该名称会立即删除,因此新进程将无法找到并删除该信号.打开信号量.
  • You create and initialize the semaphore in the parent process with sem_open(3). Give it a well-known name that the child processes will know; this name is used to find the semaphore in the system.
  • Close the semaphore in the parent, since it won't be using it.
  • Fork and execute
  • Unlink the semaphore with sem_unlink(3). This must be done exactly once; it doesn't really matter where (any process that has a reference to the semaphore object can do it). It is ok to unlink a semaphore if other processes still have it open: the semaphore is destroyed only when all other processes have closed it, but keep in mind that the name is removed immediately, so new processes won't be able to find and open the semaphore.

子进程使用众所周知的名称调用sem_open(3)来查找并获取对信号量的引用.使用信号量完成处理后,您需要使用sem_close(3)将其关闭.

The child processes call sem_open(3) with the well-known name to find and obtain a reference to the semaphore. Once a process is done with the semaphore, you need to close it with sem_close(3).

下面是我刚刚描述的示例.父进程创建一个命名的信号量,forks +执行2个子进程,每个子进程都找到并打开该信号量,并使用它们相互之间进行同步.

Below is an example of what I just described. A parent process creates a named semaphore, and forks + executes 2 child processes, each of which finds and opens the semaphore, using it to synchronize between each other.

它假定父级派生并执行./sem_chld二进制文件.请记住,信号灯的名称必须以正斜杠开头,然后是一个或多个非斜杠字符(请参见man sem_overview).在此示例中,信号灯的名称为/semaphore_example.

It assumes that the parent forks and executes the ./sem_chld binary. Keep in mind that a name for a semaphore must begin with a forward slash, followed by one or more characters that are not a slash (see man sem_overview). In this example, the semaphore's name is /semaphore_example.

这是父流程的代码:

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

#define SEM_NAME "/semaphore_example"
#define SEM_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
#define INITIAL_VALUE 1

#define CHILD_PROGRAM "./sem_chld"

int main(void) {

    /* We initialize the semaphore counter to 1 (INITIAL_VALUE) */
    sem_t *semaphore = sem_open(SEM_NAME, O_CREAT | O_EXCL, SEM_PERMS, INITIAL_VALUE);

    if (semaphore == SEM_FAILED) {
        perror("sem_open(3) error");
        exit(EXIT_FAILURE);
    }

    /* Close the semaphore as we won't be using it in the parent process */
    if (sem_close(semaphore) < 0) {
        perror("sem_close(3) failed");
        /* We ignore possible sem_unlink(3) errors here */
        sem_unlink(SEM_NAME);
        exit(EXIT_FAILURE);
    }

    pid_t pids[2];
    size_t i;

    for (i = 0; i < sizeof(pids)/sizeof(pids[0]); i++) {
        if ((pids[i] = fork()) < 0) {
            perror("fork(2) failed");
            exit(EXIT_FAILURE);
        }

        if (pids[i] == 0) {
            if (execl(CHILD_PROGRAM, CHILD_PROGRAM, NULL) < 0) {
                perror("execl(2) failed");
                exit(EXIT_FAILURE);
            }
        }
    }

    for (i = 0; i < sizeof(pids)/sizeof(pids[0]); i++)
        if (waitpid(pids[i], NULL, 0) < 0)
            perror("waitpid(2) failed");

    if (sem_unlink(SEM_NAME) < 0)
        perror("sem_unlink(3) failed");

    return 0;
}

请注意,两个孩子都终止后将调用sem_unlink(3);尽管这不是必需的,但如果在取消链接信号量的父进程与启动和打开信号量的两个子进程之间存在争用条件,则必须先调用它.不过,一般而言,只要知道所有必需的进程都已打开信号量,并且无需新进程就可以找到它,就可以立即取消链接.

Note that sem_unlink(3) is called after both children terminate; although this is not required, if it was called before there would be a race condition between the parent process unlinking the semaphore and both child processes starting up and opening the semaphore. In general, though, you can unlink as soon as you know that all required processes have opened the semaphore and no new processes will need to find it.

这是sem_chld的代码,它只是一个小的玩具程序,用于显示共享信号量的用法:

Here's the code for sem_chld, it's just a small toy program to show the usage of a shared semaphore:

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

#define SEM_NAME "/semaphore_example"
#define ITERS 10

int main(void) {
    sem_t *semaphore = sem_open(SEM_NAME, O_RDWR);
    if (semaphore == SEM_FAILED) {
        perror("sem_open(3) failed");
        exit(EXIT_FAILURE);
    }

    int i;
    for (i = 0; i < ITERS; i++) {
        if (sem_wait(semaphore) < 0) {
            perror("sem_wait(3) failed on child");
            continue;
        }

        printf("PID %ld acquired semaphore\n", (long) getpid());

        if (sem_post(semaphore) < 0) {
            perror("sem_post(3) error on child");
        }

        sleep(1);
    }

    if (sem_close(semaphore) < 0)
        perror("sem_close(3) failed");

    return 0;
}

通过在公共头文件中定义信号名称并将其包含在每个程序的代码中,可以消除使两个源文件之间的信号名称保持同步的需求.

You can eliminate the need to keep the semaphore name synchronized between the two source files by defining it in a common header file and including it in the code for each program.

请注意,在此示例中错误处理不是理想的(仅是说明性的),还有很大的改进空间.只是为了确保您决定更改此示例以适合自己的需求时,不要忘记进行正确的错误处理.

Note that error handling is not ideal in this example (it's merely illustrative), there is a lot of room for improvement. It's just there to make sure you don't forget to do proper error handling when you decide to change this example to suit your needs.

这篇关于在多个进程之间共享POSIX信号量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆