Shared memory mutex bug in C - c

When running this code the mutex (stored in shared memory between processes) permits the print to run twice.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/mman.h>
int main(){
int* shared = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
pthread_mutex_t* mutex = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
int cores = 2;
int is_son = 0;
for (int core=0; core<cores; core++){
if (!fork()){ // is son
is_son++;
printf("new son\n");
break;
}
}
if (is_son){ // only run if is son
printf("got here\n");
pthread_mutex_lock(mutex);
if (!*shared){
*shared = 1;
printf("is in (should only print once)\n");
}
pthread_mutex_unlock(mutex);
printf("left\n");
}
return 0;
}
Example output of wrong behaviour:
Explanation of the code:
We store in shared memory a boolean called shared and a mutex.
Two slave processes are created. Both try to run the print function, but only one should be permitted to do so.
The mutex is there so only one can enter the protected code at a time, and change shared's value to one, so that the next cant enter.

Related

reading and writing int from/to shared memory in c

I'm trying to make a program where a thread writes an integer into a shared memory location and then the other thread reads and prints that integer. the problem I'm facing is that the second thread keeps reading the integer as -1.
here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
struct args {
void* memptr;
sem_t* semptr;
};
void *p1(void *vargp)
{
void* memory = ((struct args*)vargp)->memptr;
sem_t* semaphore = ((struct args*)vargp)->semptr;
//sem_wait(semaphore);
//sleep(0.5);
for(int i=0; i<=10; i++)
{
if (!sem_wait(semaphore)) {
printf("got in if p1\n");
sprintf(memory, "%d", i);
sem_post(semaphore);
sleep(1);
}
}
if (!sem_wait(semaphore)) {
sprintf(memory, "%d", 0);
sem_post(semaphore);
sleep(1);
}
sleep(0.1);
}
void *p2(void *vargp)
{
void* memory = ((struct args*)vargp)->memptr;
sem_t* semaphore = ((struct args*)vargp)->semptr;
sleep(0.1);
while(1)
{
if (!sem_wait(semaphore)) {
printf("got in if p2\n");
if((int)memory == 0){
break;
}
printf("%d\n", (int)memory);
sem_post(semaphore);
sleep(1);
}
}
}
const int ByteSize = 4;
const char* SharedName = "memNameTest";
const char* SemaphoreName = "semNameTest";
int main()
{
int fd = shm_open(SharedName, O_RDWR, 0644);
ftruncate(fd, ByteSize);
void* memptr = mmap(0, ByteSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sem_t* semptr = sem_open(SemaphoreName, O_CREAT, 0644, 0);
sem_post(semptr);
struct args *Share = (struct args *)malloc(sizeof(struct args));
Share->memptr = memptr;
Share->semptr = semptr;
pthread_t thread1, thread2;
printf("Before Thread\n");
pthread_create(&thread1, NULL, p1, (void*)Share);
pthread_create(&thread2, NULL, p2, (void*)Share);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("After Thread\n");
munmap(memptr, ByteSize);
close(fd);
sem_close(semptr);
unlink(SharedName);
return 0;
exit(0);
}
I have tried changing (int)memory into *((int*)memory) but that resulted in a segmentation error.
(edit)
as suggested I tried this in a single-threaded program and got it to work as follows:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
/* the size (in bytes) of shared memory object */
const int SIZE = 4;
/* name of the shared memory object */
const char* SharedName = "memoryInt";
/* create the shared memory object */
int shm_fd = shm_open(SharedName, O_CREAT | O_RDWR, 0644);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
/* memory map the shared memory object */
void* memptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
for(int i=1; i<=10; i++){
/* write to the shared memory object */
//sprintf(memptr, "%d", i);
memcpy(memptr, &i, sizeof(int));
printf("%d\n", *((int*)memptr));
sleep(1);
}
return 0;
}
though this still doesn't work in a multi-threaded program as i get a segmentation fault.
this is the output:
Before Thread
got in if p1
Segmentation fault
First, you have to show what happen on your terminal when you compile your program.
Secondly, the function sprintf has the declaration:
sprintf(char *str, const char *format, ...);
That means the p1 will write the null terminated string of character. In your code, i dont understand why you use the void pointer memory instead of using char pointer as the description. You should verify the read/write function by using single-threaded before applying to the multi-thread.

Why does this POSIX shared memory code give a segmentation fault?

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 500;
const char *name = "name";
int fd;
char *ptr = NULL;
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) {
fd = shm_open(name,O_CREAT | O_RDWR,0666);
ftruncate(fd, SIZE);
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sprintf(ptr, "%s", "Hello, World!\n");
return 0;
}
else {
wait(NULL);
fd = shm_open(name, O_RDONLY, 0666);
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("%s\n", (char *)ptr);
}
return 0;
}
I am basically looking to create some shared memory in the child process and access it from the parent.
In the child process, the mmap works fine. When I print using the pointer returned by mmap it does in fact print Hello, World!, but the same print gives a seg fault from the parent.
In the parent (pid != 0) you opened the object O_RDONLY, but mmapped it with PROT_WRITE, MAP_SHARED. Remove the | PROT_WRITE and you are fine.
You might want to check the return values for errors the odd time.
The crash is due to this excerpt from man:
O_RDONLY Open the object for read access. A shared memory object
opened in this way can be mmap(2)ed only for read
(PROT_READ) access.
You've attempted to:
fd = shm_open(name, O_RDONLY, 0666);
// ^^^^^^^^
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// ^^^^^^^^^^^^ incorrect!
Another remark: your name should follow the man recommendation for portability:
For portable use, a shared memory object should be identified by a name
of the form /somename; that is, a null-terminated string of up to
NAME_MAX (i.e., 255) characters consisting of an initial slash,
followed by one or more characters, none of which are slashes.
Lastly, you have some unnecessary (char *) casts and always error check your return values.

How to share memory between two child processes belonging to the same parent

I've two child processes (both having same parent) launched with exec() system call and i want these two processes to map to the same file for IPC through mmap(). The problem i'm having is that one process writes the data (it's own pid) using the pointer returned by mmap() but the other process isn't able to read that data. Also i want the second child process to use that pid to know the state of first child process. Any help would be much appreciated as i'm fairly new to this.
The Parent Process:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
pid_t process, f_child, s_child;
int status;
sem_t synch;
sem_init(&synch, 1, 0);
process = fork();
if(process<0)
{
perror("Fork Failed");
exit(1);
}
if(process>)
{
//Parent!!
sem_post(&synch); // signaling to child
f_child = wait(&status);
s_child = fork();
if(s_child==0)
{
//Second Child Process!!
execlp("./secondChild", "./secondChild", NULL);
}
}
else
{
//First Child Process!!
sem_wait(&synch);
execlp("./firstChild","./firstChild", NULL);
}
return 0;
}
First Child Process:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd = shm_open("./myFile", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
int *sharedMem = mmap(0, 256, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, fd, 0);
*sharedMem = getpid();
printf("Child Process 1 wrote message : %d", *sharedMem);
exit(10);
return 0;
}
Second Child Process:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd = shm_open("./myFile", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
int *sharedMem = mmap(0, 256, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, fd, 0);
printf("Child Process 2 readmessage : %d", *sharedMem);
return 0;
}
MAP_ANONYMOUS requests anonymous memory, that is memory that is not independent of any file and the fd argument to mmap is ignored. Remove it.
If you man sem_init on linux ( at least on mine ) it says that the sem_t has to be in a shared memory location; the stack of the parent process is not a shared memory area. The manual is a bit ambiguous in this regard, as it goes on to say that a forked child inherits these mappings, but I am pretty sure that it means that a forked child inherits shared mappings.

Segmentation fault when using semaphores with POSIX shared memory

I have a problem with some simple code I'm writing to teach myself about semaphores and POSIX shared memory.
The idea is that one program, the server, opens the shared memory and writes a structure (containing a semaphore and an array) to it. Then it waits for input and after input increments the semaphore.
Meanwhile the client opens the shared memory, waits on the semaphore, and after it is incremented by the server, reads the structure.
The server seems to work okay, however I am encountering a segfault in the client at the sem_wait function, immediately (even before the server increments it). I can't figure out what is wrong.
Server code:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdbool.h>
#define ARRAY_MAX 1024
typedef struct {
sem_t inDataReady;
float array[ARRAY_MAX];
unsigned arrayLen;
} OsInputData;
int main() {
int shm_fd;
OsInputData *shm_ptr;
if((shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0666)) == -1) {
printf("shm_open failure\n");
return 1;
}
if(ftruncate(shm_fd, sizeof(OsInputData)) == -1) {
printf("ftruncate failure\n");
return 1;
}
if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
printf("mmap failure\n");
return 1;
}
sem_init(&(shm_ptr->inDataReady), true, 0);
shm_ptr->array[0] = 3.0;
shm_ptr->array[1] = 1.0;
shm_ptr->array[2] = 2.0;
shm_ptr->array[3] = 5.0;
shm_ptr->array[4] = 4.0;
shm_ptr->arrayLen = 5;
getchar();
sem_post(&(shm_ptr->inDataReady));
sem_destroy(&(shm_ptr->inDataReady));
munmap(shm_ptr, sizeof(OsInputData));
close(shm_fd);
return 0;
}
Client code:
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdbool.h>
#define ARRAY_MAX 1024
typedef struct {
sem_t inDataReady;
float array[ARRAY_MAX];
unsigned arrayLen;
} OsInputData;
int main() {
int shm_fd;
OsInputData *shm_ptr;
if((shm_fd = shm_open("/my_shm", O_RDONLY, 0666)) == -1) {
printf("shm_open failure\n");
return 1;
}
if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
printf("mmap failure\n");
return 1;
}
sem_wait(&(shm_ptr->inDataReady));
printf("%u\n", shm_ptr->arrayLen);
munmap(shm_ptr, sizeof(OsInputData));
close(shm_fd);
return 0;
}
The actual outcome depends upon your system, but in general your program contains an error. You can’t destroy a semaphore that is reachable by another process/thread. Just because you have executed a sem_post doesn’t mean that your system has switched to the process waiting for it. When you destroy it, the other guy might still be using it.
SIGSEGV, in this case, is a kindness. Few programmers check the return values of sem_wait, which can lead to programs thinking they are synchronized when they are not.
Turns out I had to open the shared memory in the client with both read and write permissions, as well as update the protections accordingly in mmap.
Quite a stupid mistake, as it's obvious the client needs write permissions as well to actually modify the semaphore.
So in the client code the following changes solved it
...
shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0755)
...
shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)
...

how to use posix named semaphore in c with shared memory between two processes on linux?

I am trying to synchronize two proccesses to read and write into shared memory. Here is a_process.c:
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#define SHM_PATH "/instant_messaging"
#define SHM_SIZE 50
#define SEM_PATH "/sem_instant_messaging"
char *sendbuff;
int main()
{
//sahred memory setting
//shm_unlink(SHM_PATH);
int shmfd;
shmfd = shm_open(SHM_PATH, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
int shm_size = SHM_SIZE;
ftruncate(shmfd, shm_size);
sendbuff = (char*) mmap(NULL, shm_size, PROT_READ | PROT_WRITE,
MAP_SHARED, shmfd, 0);
if (sendbuff == NULL) {
perror("In mmap()");
exit(1);
}
//semaphore setting
sem_unlink(SEM_PATH);
sem_t * sem1;
sem1 = sem_open(SEM_PATH, O_CREAT, S_IRUSR | S_IWUSR, 1);
printf("before while\n");
//setmemshr();
//setsem();
while (1) {
int status = sem_wait(sem1);
if (status != 0)
{
perror("in sem_wait");
}
printf("after wait\n");
printf("%s\n",sendbuff);
scanf("%s",sendbuff);
sem_post(sem1);
//sleep(3);
}
}
and here is b_process.c:
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#define SHM_PATH "/instant_messaging"
#define SHM_SIZE 50
#define SEM_PATH "/sem_instant_messaging" //dddddddddd
char *sendbuff;
int main()
{
//sahred memory setting
//shm_unlink(SHM_PATH);
int shmfd;
shmfd = shm_open(SHM_PATH, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
int shm_size = SHM_SIZE;
ftruncate(shmfd,shm_size);
sendbuff = (char*) mmap(NULL, shm_size, PROT_READ | PROT_WRITE,
MAP_SHARED, shmfd, 0);
if (sendbuff == NULL) {
perror("In mmap()");
exit(1);
}
//semaphore setting
sem_unlink(SEM_PATH);
sem_t *sem1;
sem1 = sem_open(SEM_PATH, O_CREAT, S_IRUSR | S_IWUSR, 1);
while (1) {
printf("before wait %d\n", *sem1);
int status = sem_wait(sem1);
if (status != 0)
{
perror("in sem_wait");
}
printf("after wait %d\n", *sem1);
printf("%s", sendbuff);
scanf("%s", sendbuff);
sem_post(sem1);
}
}
I have spent a lot of time debugging this and reading man pages, but it seems that although shared memory works and semaphore post and wait work within each process's address space, the two processes do not either one affect the data the other sees in the shared memory region.
Does anyone see what I am missing?
There are a few things in your code that are suspicious, but one combination of things stands out as definitely wrong: both processes perform a sem_unlink() followed immediately by a sem_open() on the semaphore path. This can have the effect of the two procs using the same semaphore only if you are absurdly lucky, such that both sem_unlink()s are performed before either sem_open() is performed. Otherwise, whichever process goes second will unlink the semaphore created by the first, and instead create and use its own. Both processes will proceed, each using its own, independent semaphore.
I also find it a bit suspicious that both processes ftruncate() the shared memory region, and especially that they do so before synchronizing (or would do if the procs were effectively synchronizing at all). I think you should make one process responsible for setting up the shared memory segment; the other needs only open and map it. Correct your semaphore initialization, and use the semaphore to ensure that the shared memory is sized before either program proceeds to using it.

Resources