有没有办法在Docker容器之间或者容器和主机之间使用POSIX信号量?

5

我正在尝试将一个多进程的应用程序迁移到Docker中。不同的进程将被放置在不同的Docker容器中。

该应用程序使用共享内存来交换数据,使用信号量来进行同步。我已经重新编译了Docker,以便不使用IPC命名空间,并且我有效地通过sudo ipcs -m检查了不同容器中共享内存缓冲区的可访问性。

问题是信号量无法正常工作。我编写了这些简单的程序来检查Docker中POSIX信号量的行为:

/*  To be compiled with -lpthread */

#include <stdio.h>
#include <fcntl.h>
#include <semaphore.h>

int main(void) {

    int ret, val;
    sem_t * mySem;

    printf("[ONE] Opening the semaphore...\n");

    mySem = sem_open("sem1", O_CREAT, 0777, 0);
    if (mySem == SEM_FAILED) {
        printf("[ONE] Error on sem_open()\n");
        return -1;
    }

    ret = sem_post(mySem);

    getchar(); // Awful way to block execution of [ONE] for a while...

    printf("[ONE] Waiting for [TWO]...\n");
    ret = sem_wait(mySem);
    printf("[ONE] Wait ended\n");

    ret = sem_unlink("sem1");
    printf("[ONE] Semaphore destroyed\n");

    return 0;
}

第二个程序是:
/* To be compiled with -lpthread */

#include <stdio.h>
#include <fcntl.h>
#include <semaphore.h>

int main(void) {

    int ret;
    int val;
    sem_t * mySem;

    printf("[TWO] Opening the semaphore...\n");

    mySem = sem_open("sem1", O_CREAT, 0777, 0);
    if (mySem == SEM_FAILED) {
        printf("[TWO] Error on sem_open()\n");
        return -1;
    }

    ret = sem_getvalue(mySem, &val);
    printf("[TWO] Semaphore's value is %d\n", val);

    printf("[TWO] Waiting for [ONE]...\n");
    ret = sem_wait(mySem);
    printf("[TWO] Wait ended\n");

    printf("[ONE] Doing sem_post() on semaphore...\n");
    ret = sem_post(mySem);

    ret = sem_close(mySem);
    printf("[TWO] Semaphore closed\n");

    return 0;
}

在两个程序中,我省略了许多控制语句,例如if (ret != 0) {...},以保持问题的可读性。
我在主机上运行了第一个程序,在Docker容器中运行了第二个程序。结果是第二个程序一直等待...
问题是:是否有可能以某种方式在Docker容器之间或容器和主机之间使用POSIX信号量?

我不明白为什么两个实例都不会永远等待。你创建了一个没有单位的信号量,然后在它上面等待? - Martin James
如果这两个程序在主机上执行,只有第一个程序会创建一个信号量:因为传递给 sem_open() 的名称相同,第二个程序不会创建新的信号量,而是使用第一个应用程序创建的信号量。然后第二个应用程序等待由第一个应用程序使用 sem_post() 解锁的信号量,以此类推... - Manuel Durando
能否在Docker容器之间共享内存? - Thomasleveil
@ManuelDurando 哈哈,对不起啊。我猜你没有找到Docker在命名空间共享方面取得进展的证据。 - Thomasleveil
@Thomas 我修改并重新编译了Docker,排除了IPC命名空间,以便通过shmget()等方式获取共享内存。 - Manuel Durando
显示剩余4条评论
1个回答

2
我使用了在这个问题中解释的Docker容器之间共享内存来解决问题。
以下代码是这个教程的修改版本。 文件 server.c
/* To be compiled with -lpthread */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <semaphore.h>

#define SHM_SIZE     1000

int main(void) {

    int shmid;
    key_t key;
    char *shm;

    sem_t * mySem;

    /* We'll name our shared memory segment "5678" */
    key = 5678;

    /* Create the segment.*/
    if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666)) < 0) {
        perror("shmget");
        exit(1);
    }

    /* Now we attach the segment to our data space */
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    /* Create a new semaphore */
    mySem = sem_open("sem1", O_CREAT, 0777, 0);

    /* Copy the semaphore on the shared memory segment */  
    memcpy(shm, mySem, sizeof(*mySem));

    /* Do stuff ... */

    /* REMEMBER TO USE THE SHARED MEMORY SEGMENT */
    /* AND NOT THE LOCAL mySem, USE (sem_t*)shm INSTEAD! */

    /* Finally, we wait until the other process 
     * changes the first character of our memory
     * to '*', indicating that it has read what 
     * we put there.
     */
    while (*shm != '*')
        sleep(1);

    /* Mark the memory segment to be destroyed */
    shmctl(shmid, IPC_RMID, NULL);

    /* Detach of the memory segment */
    shmdt(&shm);

    sem_unlink("sem1");

    return 0;
}

File client.c

/* To be compiled with -lpthread */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <semaphore.h>

#define SHM_SIZE     1000

int main(void) {

    int shmid;
    key_t key;
    char *shm;

    int ret, val;

    key = 5678;

    if ((shmid = shmget(key, SHM_SIZE, 0666)) < 0) {
        perror("shmget");
        exit(1);
    }

    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    /* SEMAPHORE IS IN THE SHARED MEMORY SEGMENT */
    /* USE (sem_t*)shm TO ACCESS IT */

    *shm = '*';

    shmdt(&shm);

    sem_close("sem1");

    return 0;
}

为了可读性,代码示例中省略了许多控件。

我在主机上运行服务器,在Docker容器内运行客户端,并检查了信号量是否可以从两个进程访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接