I'm trying to migrate a multiprocess application to Docker. Different processes will be placed in different Docker container.
The application uses shared memory to exchange data and semaphores to synchronize. I already recompiled Docker in order to do not use the IPC namespace and I effectively checked with sudo ipcs -m
that the shared memory buffers are accessible from the different containers.
The problem is that semaphores are not working. I wrote these simple programs to check the behavior of POSIX semaphores in Docker:
/* 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;
}
The second program is:
/* 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;
}
In both I omitted lots of controls like if (ret != 0) {...}
in order to maintain readability of the question.
I run the first program on the host machine, the second one in a Docker container. The result is that the second program waits forever...
The question is: is it possible in some way to use POSIX semaphores between Docker containers or between a container and the host?
I solved the problem using shared memory between Docker containers as explained in this question.
The following code is a modified version of this tutorial.
File 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;
}
The code examples miss lots of controls due to readability purposes.
I run the server on the host machine, the client inside a Docker container and checked that the semaphore was accessible from both processes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With