Can not wait on shared semaphore - c

I have to program Readers-Writers Problem in C without using threads. I have used this to initialize shared semaphores:
/* initialize semaphores for shared processes */
resource = sem_open ("/rSem", 0644, O_CREAT | O_EXCL, 1);
sem_unlink ("/rSem");
mutex = sem_open ("/mSem", 0644, O_CREAT | O_EXCL, 1);
sem_unlink ("/mSem");
but while running child process
sem_wait(resource);
terminates the program.
here is my complete code:
/* Includes */
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <errno.h> /* Errors */
#include <stdio.h> /* Input/Output */
#include <stdlib.h> /* General Utilities */
#include <pthread.h> /* POSIX Threads */
#include <string.h> /* String handling */
#include <semaphore.h> /* Semaphore */
#include <sys/mman.h>
#include <fcntl.h> /* O_CREAT, O_EXEC */
/* prototype for thread routine */
void writer ( int , int *);
void reader ( int , int *, int *);
void multipleFork ( int );
/* global variables */
sem_t *mutex;
sem_t *resource;
int main(int argc, char **argv)
{
int * Buffer = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
int * readcount = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
/* initialize semaphores for shared processes */
resource = sem_open ("/rSem", 0644, O_CREAT | O_EXCL, 1);
sem_unlink ("/rSem");
mutex = sem_open ("/mSem", 0644, O_CREAT | O_EXCL, 1);
sem_unlink ("/mSem");
pid_t pid = fork();
if (pid == 0)
writer(1, Buffer);
else
reader(3, Buffer, readcount);
sem_destroy(resource);
sem_destroy(mutex);
exit(0);
} /* main() */
void writer ( int n , int * Buffer)
{
multipleFork(n);
sleep(1);
while(1){
usleep(rand()%3000);
sem_wait(resource);
//<CRITICAL Section>
printf("The writer (%d) ‫‪acquires‬‬ ‫‪the‬‬ ‫‪lock.\n‬‬", getpid());
(*Buffer)++;
printf("The writer (%d) writes ‫‪the‬‬ ‫‪value %d.\n‬‬", getpid(), *Buffer);
sleep(1);
printf("The writer (%d) releases ‫‪the‬‬ ‫‪lock.‬‬\n", getpid());
//<CRITICAL Section>
sem_post(resource);
sleep(1);
}
}
void reader( int n , int * Buffer, int * readcount) {
multipleFork(n);
while(1){
usleep(rand()%3000);
sem_wait(mutex);
usleep(rand()%3000);
if ((*readcount) == 0)
{
sem_wait(resource);
printf("The first reader (%d) acquires the lock.%d\n", getpid(), *readcount);
(*readcount)++;
}
else if ((*readcount) > 0)
{
printf("The reader (%d) acquires the lock.%d\n", getpid(), *readcount);
(*readcount)++;
}
sem_post(mutex);
//<CRITICAL Section>
printf("Reader (%d) reads the value %d.%d\n", getpid(), *Buffer, *readcount);
sleep(1);
//<CRITICAL Section>
sem_wait(mutex);
(*readcount)--;
if ((*readcount) == 0)
{
printf("The last reader (%d) releases the lock.\n", getpid());
sem_post(resource);
}
else
printf("The reader (%d) releases the lock.\n", getpid());
sem_post(mutex);
sleep(1);
}
}
void multipleFork (int n)
{
while(n-1 > 0){
pid_t pid = fork();
if (pid == 0){
return;
}
else
n--;
}
return;
}

I have used
resource = sem_open ("/rSem", 0644, O_CREAT | O_EXCL, 1);
instead of
resource = sem_open ("/rSem", O_CREAT | O_EXCL, 0644, 1);

Related

Processes with group of 2 semaphores and shared memory

I write a program containing two processes: the first one contains a group of two semaphores and creates the child process that reads all data in the shared memory segment and prints them.
In the second one, the child process computes the data using a compute function that returns 0 when all data are computed. It transmits them to the parent through the shared memory segment.
To write data:
On the 1st semaphore the child makes P and the parent make V.
On the 2nd semaphore the child makes V and the parent make P.
But as I'm new in this topic and still getting hardness to understand, it seems like I'm doing something wrong because it's not working as it has to be.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/wait.h>
int sum =0;
int compute(int data){
sum += data;
return sum;
}
int main(){
int i;
int shm_id;
int data;
pid_t pid;
key_t shm_key;
sem_t *sem;
// unsigned int sem_value =2;
shm_key = ftok("/dev/null", 65);
shm_id = shmget(shm_id, sizeof(int), 0644 | IPC_CREAT);
if (shm_id < 0){
perror("shmgget");
exit(EXIT_FAILURE);
}
// data = shmat(shm_id, NULL, 0);
sem = sem_open("semaphore", O_CREAT | O_EXCL, 0644, 2);
for (i = 0; i < 2; i++){
pid = fork();
if (pid < 0)
{
perror("fork");
sem_unlink("semaphore");
sem_close(sem);
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
break;
}
}
if (pid == 0)
{
puts("Enter the data:");
scanf("%d", &data);
//child process
sem_wait(sem);
printf("Child - %d is in critical section\n", i);
sleep(1);
puts("Enter the data:");
scanf("%d", &data);
// *shrd_value += data;
printf("Child - %d: new value of data = %d\n", i, data);
printf("Child - %d: sum of whole data by far = %d\n", i, compute(data));
sem_post(sem);
exit(EXIT_SUCCESS);
}
else if (pid > 0)
{
//parent process
while (pid = waitpid(-1, NULL, 0))
{
if (errno == ECHILD)
{
break;
}
}
puts("All children exited");
shmdt(&data);
shmctl(shm_id, IPC_RMID, 0);
sem_unlink("semaphore");
sem_close(sem);
exit(0);
}
}
Output:
Enter the data:
Enter the data:
2
Child - 0 is in critical section
1Enter the data:
Child - 1 is in critical section
Enter the data:
3
Child - 0: new value of data = 3
Child - 0: sum of whole data by far = 3
2
Child - 1: new value of data = 2
Child - 1: sum of whole data by far = 2
All children exited
I have also modified the way they write to shared memory: they write directly at the address given by shmat call that is missing in your code.
I have fixed some bugs and simplifed the code (removed the array - added detailed logging especially before and after entering the critial section):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/wait.h>
int main(){
int i;
int shm_id;
pid_t pid;
int *addr;
int data;
pid_t current_pid;
key_t shm_key;
sem_t *sem;
shm_key = ftok("/dev/null", 65);
shm_id = shmget(shm_key, sizeof(int), 0644 | IPC_CREAT);
if (shm_id < 0){
perror("shmget");
exit(EXIT_FAILURE);
}
sem_unlink("semaphore");
sem = sem_open("semaphore", O_CREAT, 0644, 1);
if (sem == SEM_FAILED) {
perror("sem_open");
exit(EXIT_FAILURE);
}
addr = (int *) shmat(shm_id, (void *) 0, 0);
if (addr == (void *) -1) {
perror("shmat");
exit(EXIT_FAILURE);
}
*addr = 0;
for (i = 0; i < 2; i++){
pid = fork();
if (pid < 0)
{
perror("fork");
sem_close(sem);
sem_unlink("semaphore");
exit(EXIT_FAILURE);
}
}
if (pid == 0)
{
current_pid = getpid();
printf("Child %d: waiting for critical section \n", current_pid);
sem_wait(sem);
printf("Child %d: enters in critical section \n", current_pid);
printf("child %d: Enter the data:\n", current_pid);
scanf("%d", &data);
printf("Child %d: new value of data = %d\n", current_pid, data);
printf("Child %d: sum of whole data so far = %d\n", current_pid, *addr += data);
sem_post(sem);
printf("Child %d exits from critical section\n", current_pid);
exit(EXIT_SUCCESS);
}
else if (pid > 0)
{
//parent process
while (pid = waitpid(-1, NULL, 0))
{
if (errno == ECHILD)
{
break;
}
}
puts("All children exited");
shmdt(addr);
shmctl(shm_id, IPC_RMID, 0);
sem_close(sem);
sem_unlink("semaphore");
exit(0);
}
exit(0);
}
Note that semaphore initial value must be 1 to have a true critical section for 2 processes.
I have also removed the sleep calls and we can see that one of the process is waiting:
Child 22514: waiting for critical section
Child 22514: enters in critical section
child 22514: Enter the data:
Child 22515: waiting for critical section
333
Child 22514: new value of data = 333
Child 22514: sum of whole data so far = 333
Child 22514 exits from critical section
Child 22515: enters in critical section
child 22515: Enter the data:
666
Child 22515: new value of data = 666
Child 22515: sum of whole data so far = 999
Child 22515 exits from critical section
All children exited
All children exited
Here's the code with producer and consumer process
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h> // O_CREAT, O_EXEC
#include <errno.h> // errno, ECHILD
#include <unistd.h>
#include <sys/shm.h> // shmat(), IPC_RMID
#include <sys/wait.h>
#include <semaphore.h> // sem_open(), sem_destroy(), sem_wait()...
#include <sys/types.h> // key_t, sem_t, pid_t
#include <pthread.h>
#define BUFF 10
typedef struct data{
int buff[BUFF];
int size;
int index;
}DATA;
int main(int argc, char const *argv[])
{
sem_t *full, *empty, *access;
key_t shm_key;
int shm_id;
full = sem_open ("fullname", O_CREAT , 0644, 15);
empty = sem_open ("empty", O_CREAT , 0644, 0);
access = sem_open ("access", O_CREAT , 0644, 1);
if (argc!=2)
{
exit(1);
}
int value=atoi(argv[1]);
//initialize a shared variable in shared memory
shm_key = ftok("/dev/null", 60);
shm_id = shmget(shm_key, sizeof(DATA), 0);
// shared memory error check
if (shm_id < 0){
shm_id = shmget(shm_key, sizeof(DATA), 0644 | IPC_CREAT);
DATA *data = (DATA*) shmat (shm_id, NULL, 0);
data->size=0;
data->index=0; //index
}
printf("Shared memory id: %d\n",shm_id );
printf("Checking buffer...,\n");
//If in the buffer have free space then will wait for consumer to consume the data\n"
sem_wait(empty);
printf("\nLocking buffer to produce data\n");
sem_wait(access);
//initialize a shared variable in shared memory
shm_key = ftok("/dev/null", 60);
shm_id = shmget(shm_id, sizeof(DATA), 0644 | IPC_CREAT);
// shared memory error check
if (shm_id < 0){
perror("semaphore");
exit(EXIT_FAILURE);
}
//Shared variable
DATA *data = (DATA*) shmat (shm_id, NULL, 0);
int index=(data->size + data->index) % 15;
data->buff[index]=value;
data->size++;
printf("%d is located in %d on the buffer\n",value,index );
//consusming
// attach data to shared memory
index=data->index;
value=data->buff[index];
printf("%d now consumed\n",value );
data->size--;
data->index++;
sem_post(access);
sem_post(full);
return 0;
}

I share memory in C between a main process and his children but I have trouble syncronising their actions

I have a program that is supposed to do this:
The main program creates a chunk of shared memory (to share with his future children) the size of a struct called ClientInfo which contains 2 integers and a string. Then the program asks the user for a number which is stored in the variable n
The main program creates n children.Then the children wait for a SIGUSR1 signal from their father.
The main program sends a SIGUSR1 signal to all his children.
Each child reads a string from the terminal, writes it in the shared memory and also increments in one unit both shared integers. Then he sends a SIGUSR1 to his father, sleeps between 1 and 10 seconds and then ends.
Each time the father recieves a SIGUSR1 it prints the contenent of the shared memory, then only ends when all of his children end.
The "catch" is that this is college homework and they told us that the father must be able to print the content of the shared memory one time for each children, so n times in total. Also we can't use sigwait() or global variables (unless global variables are the only way).
Also each time I run the program it just hangs indefinitely asfter asking for n
I know there must be some sort of race condition but I'm really bad at that and I can't figure out what's wrong.
Thank you in advance.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define SHM_NAME "/shm_example"
#define SEM1 "/example_sem1"
#define SEM2 "/example_sem2"
#define NAME_MAX 100
typedef struct{
int previous_id; //!< Id of the previous client.
int id; //!< Id of the current client.
char name[NAME_MAX]; //!< Name of the client.
} ClientInfo;
int main(void) {
int i,n,*pids;
int fd_shm;
int error;
struct sigaction act;
ClientInfo *example_struct;
sigset_t mask, oldmask;
sem_t *sem_write = NULL,*sem_read = NULL;
sigemptyset(&mask);
sigemptyset(&oldmask);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
printf("Introduzca un numero:\n");
scanf("%d",&n);
if(!(pids = malloc(n*sizeof(int))))
exit(EXIT_FAILURE);
if ((sem_write = sem_open(SEM1, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
perror("sem_open");
exit(EXIT_FAILURE);
}
if ((sem_read = sem_open(SEM2, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
perror("sem_open");
exit(EXIT_FAILURE);
}
sigemptyset(&(act.sa_mask));
act.sa_flags = 0;
act.sa_handler = SIG_IGN;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
fd_shm = shm_open(SHM_NAME,O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);
if(fd_shm == -1) {
fprintf (stderr, "Error creating the shared memory segment \n");
return EXIT_FAILURE;
}
error = ftruncate(fd_shm, sizeof(ClientInfo));
if(error == -1) {
fprintf (stderr, "Error resizing the shared memory segment \n");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
/* Map the memory segment */
example_struct = (ClientInfo *)mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);
if(example_struct == MAP_FAILED) {
fprintf (stderr, "Error mapping the shared memory segment \n");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
(example_struct->previous_id)=-1;
(example_struct->id)=0;
for(i=0;i<n;i++){
pids[i] = fork();
if (pids[i] < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pids[i] == 0) {
char nombre[NAME_MAX];
srand(getpid() ^ (i * 1091));
sigsuspend(&oldmask);
sem_wait(sem_write);
(example_struct->previous_id)++;
printf("Introduzca un nombre:\n");
scanf("%s",nombre);
memcpy(example_struct->name, nombre, sizeof(nombre));
(example_struct->id)++;
kill(getppid(),SIGUSR1);
sem_post(sem_write);
sleep(1 + (rand()%10));
exit(EXIT_SUCCESS);
}
}
sigprocmask(SIG_UNBLOCK, &mask, &oldmask);
kill(0,SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
while(1){
sigsuspend(&oldmask);
/*if(wait(NULL)<0){
sem_close(sem_write);
sem_close(sem_read);
sem_unlink(SEM1);
sem_unlink(SEM2);
munmap(example_struct, sizeof(*example_struct));
shm_unlink(SHM_NAME);
exit(EXIT_SUCCESS);
}*/
sem_wait(sem_read);
sem_wait(sem_write);
sem_post(sem_read);
printf("El cliente es %s con id %d y el previo es %d\n",example_struct->name,example_struct->id,example_struct->previous_id);
fflush(stdout);
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
sem_wait(sem_read);
sem_post(sem_write);
sem_post(sem_read);}
}
You can try something like that:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdatomic.h>
#define SHM_NAME "/shm_example"
#define NAME_MAX 100
typedef struct{
char name[NAME_MAX]; //!< Name of the client.
} ClientInfo;
atomic_bool done = ATOMIC_VAR_INIT(false);
void child_handler(int dummy) {
(void)dummy;
done = true;
}
int main(void) {
int i,n,*pids;
int fd_shm;
int error;
struct sigaction act;
ClientInfo *example_struct;
printf("Introduzca un numero:\n");
scanf("%d",&n);
if(!(pids = malloc(n*sizeof(int))))
exit(EXIT_FAILURE);
sigemptyset(&(act.sa_mask));
act.sa_flags = 0;
act.sa_handler = child_handler;
if (sigaction(SIGUSR1, &act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
fd_shm = shm_open(SHM_NAME,O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);
if(fd_shm == -1) {
fprintf (stderr, "Error creating the shared memory segment \n");
return EXIT_FAILURE;
}
error = ftruncate(fd_shm, sizeof(ClientInfo));
if(error == -1) {
fprintf (stderr, "Error resizing the shared memory segment \n");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
/* Map the memory segment */
example_struct = (ClientInfo *)mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0);
if(example_struct == MAP_FAILED) {
fprintf (stderr, "Error mapping the shared memory segment \n");
shm_unlink(SHM_NAME);
return EXIT_FAILURE;
}
for (i = 0; i < n ; i++) {
pids[i] = fork();
if (pids[i] < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pids[i] == 0) {
/* Child */
while (!done) {
/* Wait for signal */
sleep(1);
}
printf("child %d wakes up\n", getpid());
sprintf(example_struct->name, "my pid is %d", getpid());
kill(getppid(),SIGUSR1);
sleep(1 + (rand()%10));
exit(EXIT_SUCCESS);
}
}
/* only father here */
for (i = 0; i < n; i++) {
done = false;
kill(pids[i], SIGUSR1);
printf("Waiting child %d\n", pids[i]);
while (!done) {
/* Wait for signal */
sleep(1);
}
printf("Answer from %d: %s\n", pids[i], example_struct->name);
wait(NULL);
}
}
In the end, I don't really understand why you used semaphores if you are asked to use signal only, thus I removed them. I also removed the id do get a less chatty code, you may add them back if you need it.
The point here is I perform the wait with a while() loop waiting for a boolean atomic variable.
So the father trig a signal on the first child, then waits for it to signal back, then do the same with the next one, and so on...
so you get such a sequence:
$ ./example
Introduzca un numero:
5
Waiting child 14314
child 14314 wakes up
Answer from 14314: my pid is 14314
Waiting child 14315
child 14315 wakes up
Answer from 14315: my pid is 14315
Waiting child 14316
child 14316 wakes up
Answer from 14316: my pid is 14316
Waiting child 14317
child 14317 wakes up
Answer from 14317: my pid is 14317
Waiting child 14318
child 14318 wakes up
Answer from 14318: my pid is 14318

Read Only shared memory segmentation fault [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm struggling with shared mem on linux paltform.
Cosider the following code:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#define SEM_NAME "mysem"
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
sleep(1);
}
return 0;
}
If I launch the app for a read only shared memory I get, as expected, segmentation fault the first time *ptr is incremented inside main loop.
I'm working on a lib that abstract Linux shared memory.
This lib will be deployed to third part developers that will implement some processes for my application on an embedded target.
This lib will implement "global variables" between processes. I was wondering if I can avoid to develop get and set function and simply return address of allocated memory.
In case of wrong permission access I want to give to caller infos about what was wrong in its code. Read segmentation fault on terminal and process termination does not give user a good information.
EDIT2
After #Ctx answer I tried the following solution but it works the first segmentation fault. The second trigger standard segmentation fault and pogram terminate.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <setjmp.h>
#define SEM_NAME "mysem"
#define TEST 1
jmp_buf env;
void segvhandler(int arg) {
longjmp(env, 1);
}
bool Test ( int *ptr, sem_t *mutex, pid_t PID)
{
#if (TEST == 1)
signal(SIGSEGV, segvhandler);
#elif (TEST == 2)
sig_t segvhandler_OLD = signal(SIGSEGV, segvhandler);
#endif
int val = setjmp(env);
if (val != 0)
{
printf("Segmentation fault catched.\n");
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return false;
}
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return true;
}
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
Test (ptr, mutex, PID);
sleep(1);
}
return 0;
}
Per the mmap() man page:
Use of a mapped region can result in these signals:
SIGSEGV
Attempted write into a region mapped as read-only.
If you want to proceed if the modification doesn't work, you can install a signal handler for SIGSEGV and use (sig)setjmp/longjmp to continue execution at a defined point:
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
jmp_buf env;
void segvhandler(int arg) {
siglongjmp(env, 1);
}
void somefunc(void) {
char *ptr = NULL;
signal(SIGSEGV, segvhandler);
if (!sigsetjmp(env, 1)) {
// Direct invocation, try the memory access
*ptr++;
}
signal(SIGSEGV, SIG_DFL);
}
int main (void) {
while (1) {
somefunc();
printf("One more iteration...\n");
}
exit(EXIT_SUCCESS); // Never reached
}
sigsetjmp(env, 1) also saves the blocked signals in env, when it's second argument is non-zero and siglongjmp() then restores these. Otherwise, the signal will still be blocked after longjmp(), since it is not a real return from the signal handler.
Keep in mind that you should only have the handler installed directly before you make the memory access in question and deinstall it afterwards.
a few minutes with the debugger shows the program crashes on the call to sem_wait().
if, after the call to sem_open() insert:
if( SEM_FAILED == mutex )
{
perror( "sem_open failed" );
exit( EXIT_FAILURE );
}
then move the statement:
sem_unlink(SEM_NAME);
to before the statement:
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
then it will become obvious that the remaining problem is in this statement:
printf("PID %d Count: %d\n", PID, (*ptr)++);
which causes a bus error signal to be raised. this bus error signal occurs on the very first pass through the while() loop.
there is a simple cause.
the printf() statement, last parameter is trying to both read and write the memory mapped file, but the memory mapping was only for (depending on the command line parameter) either 'PROT_READ' which allows reading or 'PROT_WRITE' which allows writing. the parameter to the call to mmap() needs to include both capabilities AND the call to open() also needs to
have the mode: O_RDWR. (the open() and the mmap() modes need to match
This is the corrected code after Ctx answer. I also found out THIS that is useful to understan why longjmp is not the right solution with signals.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <setjmp.h>
#define SEM_NAME "mysem"
#define TEST 1
jmp_buf env;
void segvhandler(int arg) {
siglongjmp(env, 1);
}
bool Test ( int *ptr, sem_t *mutex, pid_t PID)
{
#if (TEST == 1)
signal(SIGSEGV, segvhandler);
#elif (TEST == 2)
sig_t segvhandler_OLD = signal(SIGSEGV, segvhandler);
#endif
int val = sigsetjmp(env, 1);
if (val != 0)
{
printf("Segmentation fault catched.\n");
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return false;
}
sem_wait(mutex);
printf("PID %d Count: %d\n", PID, (*ptr)++);
sem_post(mutex);
#if (TEST == 1)
signal(SIGSEGV, SIG_DFL);
#elif (TEST == 2)
signal(SIGSEGV, segvhandler_OLD);
#endif
return true;
}
int main (int argc, char *argv[])
{
int fd, zero = 0;
int *ptr;
sem_t *mutex;
pid_t PID = getpid();
int mmap_prot = PROT_WRITE;
if (argc < 2)
{
printf(" Usage: Test [OPTION]\n\tW = Write Only\n\tR = Read Only\n");
return 1;
}
if (*argv[1] == 'W')
{
fd = open("Test_SHM", O_RDWR | O_CREAT, -1);
if (fd == -1)
perror("open");
write(fd, &zero, sizeof(int));
}
else
{
fd = open("Test_SHM", O_RDONLY| O_CREAT, -1);
if (fd == -1)
perror("open");
mmap_prot = PROT_READ;
}
ptr = mmap(NULL, sizeof(int), mmap_prot, MAP_SHARED, fd, 0);
close(fd);
if (ptr == MAP_FAILED)
{
perror("mmap");
return 1;
}
// create, initialize, and unlink semaphore
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, -1, 1);
sem_unlink(SEM_NAME);
setbuf(stdout, NULL); /* stdout is unbuffered */
printf("Shared Mem ready..\n");
while(1)
{
Test (ptr, mutex, PID);
sleep(1);
}
return 0;
}

What alternatives I have against sleep() to synchronize transfer between parent and child process?

I'm facing a synchronization problem, the problem I'm trying to solve involves sending string from parent to child, reversing it and sending it back to child ( using shared memory ).
However to make sure child is waiting for parent I'm using sleep(3) to give 3 seconds to parent process to enter string, however this is limiting my programs efficiency, I don't want to force user to wait for 3 seconds.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h> /* Needed for the wait function */
#include <unistd.h> /* needed for the fork function */
#include <string.h> /* needed for the strcat function */
#define SHMSIZE 27
int main() {
int shmid;
char *shm;
if(fork() == 0) {
sleep(3);
shmid = shmget(29009, SHMSIZE, 0);
shm = shmat(shmid, 0, 0);
printf ("Child : Reading %s \n",shm) ;
int len=strlen(shm);
char rev[100],temp;
int i = 0;
int j = strlen(shm) - 2;
while (i < j) {
temp = shm[i];
shm[i] = shm[j];
shm[j] = temp;
i++;
j--;
}
shmdt(shm);
}else {
shmid = shmget(29009, SHMSIZE, 0666 | IPC_CREAT);
shm = shmat(shmid, 0, 0);
printf("Parent : Enter String \n ");
char *s = (char *) shm;
*s = '\0';
char a[100];
fgets(a,100,stdin);
strcat(s,a);
printf ("Parent: sending %s \n",shm);
sleep(3);
printf("Parent: receiving %s" ,shm);
shmdt(shm);
}
return 0;
}
Question:
How could this be implemented in a better way, so that the program is more efficient?
I would suggest using semaphores, this is not a case where you use 'sleep':
http://man7.org/linux/man-pages/man7/sem_overview.7.html
You can use them like in this example:
http://www.csc.villanova.edu/~mdamian/threads/posixsem.html
You cannot know for sure that it will not take more than 3 seconds, so sleep is a realy bad choice. So, it goes something like this:
#include <stdio.h>
#include <semaphore.h>
int main(void)
{
sem_t *sem = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_ANONYMOUS, -1, 0);
sem_init(sem, 1, 1);
if(fork() == 0) {
printf("Child: Waiting to acquire semaphore\n");
sem_wait(sem);
printf("Child acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem);
} else {
printf("Parent: Waiting to acquire semaphore\n");
sem_wait(sem);
printf("Parent acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem);
}
sem_destroy(sem);
return 0;
}
Oh and if you want it parent to be followed by child always (or the other way around), you can use two semaphores, and initialize them accordingly(with 1 and 0, or 0 and 1).
sem_wait(sem1);
printf("Parent acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem2);
/* Other things will be happening here */
sem_wait(sem2);
printf("Child acquires lock\n");
/* do whatever you want then relese*/
sem_post(sem1);
Edit
If you do not have to use shared memory, it would be better to do the communication with sockets.
Thanks to amazing StackOverflow community for coming to my rescue! I have resolved solved the issue using semaphores! I'm sharing my final code so it can be of use for anyone who gets struck in a situation like mine!
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h> /* Needed for the wait function */
#include <unistd.h> /* needed for the fork function */
#include <string.h> /* needed for the strcat function */
#include <semaphore.h>
#include <sys/mman.h>
#include<fcntl.h>
#include<stdlib.h>
#define SHMSIZE 27
typedef struct {
sem_t one;
sem_t two;
} SemPair;
int main() {
int shm = shm_open("/test", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(shm, sizeof(sem_t));
SemPair *sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
sem_init(&(sem->one), 1, 0);
sem_init(&(sem->two), 1, 0);
int shmid;
char *shmz;
if(fork() == 0) {
sem_wait(&(sem->one));
shmid = shmget(29009, SHMSIZE, 0);
shmz = shmat(shmid, 0, 0);
printf ("Child : Reading %s \n",shmz) ;
int len=strlen(shmz);
char rev[100],temp;
int i = 0;
int j = strlen(shmz) - 2;
while (i < j) {
temp = shmz[i];
shmz[i] = shmz[j];
shmz[j] = temp;
i++;
j--;
}
shmdt(shmz);
sem_post(&(sem->two));
}
else {
shmid = shmget(29009, SHMSIZE, 0666 | IPC_CREAT);
shmz = shmat(shmid, 0, 0);
printf("Parent : Enter String \n ");
char *s = (char *) shmz;
*s = '\0';
char a[100];
fgets(a,100,stdin);
strcat(s,a);
printf ("Parent: sending %s \n",shmz);
sem_post(&(sem->one));
sem_wait(&(sem->two));
printf("Parent: receiving %s" ,shmz);
shmdt(shmz);
}
return 0;
}

Share condition variable & mutex between processes: does mutex have to locked before?

I need to some little help to understand how to use condition variables in C to resolve an exercise. Here is a little example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#define OKTOWRITE "/oktowrite"
#define MESSAGE "/message"
#define MUTEX "/lock"
int main(int argc, char** argv)
{
pthread_cond_t* condition;
pthread_mutex_t *mutex;
char* message;
int des_cond, des_msg, des_mutex;
int mode = S_IRWXU | S_IRWXG;
des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_mutex < 0)
{
perror("failure on shm_open on des_mutex");
exit(1);
}
if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1)
{
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
mutex = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),
PROT_READ | PROT_WRITE, MAP_SHARED, des_mutex, 0);
if (mutex == MAP_FAILED )
{
perror("Error on mmap on mutex\n");
exit(1);
}
pthread_mutex_init(mutex, NULL );
des_cond = shm_open(OKTOWRITE, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_cond < 0)
{
perror("failure on shm_open on des_cond");
exit(1);
}
if (ftruncate(des_cond, sizeof(pthread_cond_t)) == -1)
{
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
condition = (pthread_cond_t*) mmap(NULL, sizeof(pthread_cond_t),
PROT_READ | PROT_WRITE, MAP_SHARED, des_cond, 0);
if (condition == MAP_FAILED )
{
perror("Error on mmap on condition\n");
exit(1);
}
pthread_cond_init(condition, NULL );
if (!fork())
{
sleep(3);
pthread_mutex_lock(mutex);
pthread_cond_signal(condition);
pthread_mutex_unlock(mutex);
printf("son signaled\n");
exit(0);
}
else
{
printf("wait on condition\n");
pthread_mutex_lock(mutex);
pthread_cond_wait(condition, mutex);
pthread_mutex_unlock(mutex);
printf("Signaled by son process, wake up\n");
pthread_mutex_destroy(mutex);
pthread_cond_destroy(condition);
shm_unlink(OKTOWRITE);
shm_unlink(MESSAGE);
shm_unlink(MUTEX);
return 0;
}
}
The problem is that the father of the process keeps on being locked, even after son's signaling. Everything is in shared memory (using shm_open and mmap) so the condition should be the same for both the processes.
Am I maybe making a mistake by locking the mutex before calling wait or signal?
EDIT:
Thanks to all who helped me. Here's the right code with the CRITICAL parts marked:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#define OKTOWRITE "/condwrite"
#define MESSAGE "/msg"
#define MUTEX "/mutex_lock"
int main(int argc, char** argv) {
pthread_cond_t* condition;
pthread_mutex_t* mutex;
char* message;
int des_cond, des_msg, des_mutex;
int mode = S_IRWXU | S_IRWXG;
des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_mutex < 0) {
perror("failure on shm_open on des_mutex");
exit(1);
}
if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
mutex = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),
PROT_READ | PROT_WRITE, MAP_SHARED, des_mutex, 0);
if (mutex == MAP_FAILED ) {
perror("Error on mmap on mutex\n");
exit(1);
}
des_cond = shm_open(OKTOWRITE, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_cond < 0) {
perror("failure on shm_open on des_cond");
exit(1);
}
if (ftruncate(des_cond, sizeof(pthread_cond_t)) == -1) {
perror("Error on ftruncate to sizeof pthread_cond_t\n");
exit(-1);
}
condition = (pthread_cond_t*) mmap(NULL, sizeof(pthread_cond_t),
PROT_READ | PROT_WRITE, MAP_SHARED, des_cond, 0);
if (condition == MAP_FAILED ) {
perror("Error on mmap on condition\n");
exit(1);
}
/* HERE WE GO */
/**************************************/
/* set mutex shared between processes */
pthread_mutexattr_t mutexAttr;
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mutexAttr);
/* set condition shared between processes */
pthread_condattr_t condAttr;
pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(condition, &condAttr);
/*************************************/
if (!fork()) {
sleep(10);
pthread_mutex_lock(mutex);
pthread_cond_signal(condition);
printf("son signaled\n");
pthread_mutex_unlock(mutex);
exit(0);
}
else {
printf("father waits on condition\n");
pthread_mutex_lock(mutex);
pthread_cond_wait(condition, mutex);
pthread_mutex_unlock(mutex);
printf("Signaled by son process, wake up!!!!!!!!\n");
pthread_condattr_destroy(&condAttr);
pthread_mutexattr_destroy(&mutexAttr);
pthread_mutex_destroy(mutex);
pthread_cond_destroy(condition);
shm_unlink(OKTOWRITE);
shm_unlink(MESSAGE);
shm_unlink(MUTEX);
}
return 0;
}
To be shareable between processes a mutex needs to be initialised accordingly via a properly initialised attribute: http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setpshared.html
#include <pthread.h>
...
pthread_mutex_t * pmutex = NULL;
pthread_mutexattr_t attrmutex;
/* Initialise attribute to mutex. */
pthread_mutexattr_init(&attrmutex);
pthread_mutexattr_setpshared(&attrmutex, PTHREAD_PROCESS_SHARED);
/* Allocate memory to pmutex here. */
/* Initialise mutex. */
pthread_mutex_init(pmutex, &attrmutex);
/* Use the mutex. */
/* Clean up. */
pthread_mutex_destroy(pmutex);
pthread_mutexattr_destroy(&attrmutex);
(error checking left out for the sake of this example's readability)
The same applies to a condition variable which should be shared between processes: http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_setpshared.html
#include <pthread.h>
...
pthread_cond_t * pcond = NULL;
pthread_condattr_t attrcond;
/* Initialise attribute to condition. */
pthread_condattr_init(&attrcond);
pthread_condattr_setpshared(&attrcond, PTHREAD_PROCESS_SHARED);
/* Allocate memory to pcond here. */
/* Initialise condition. */
pthread_cond_init(pcond, &attrcond);
/* Use the condition. */
/* Clean up. */
pthread_cond_destroy(pcond);
pthread_condattr_destroy(&attrcond);
(error checking left out for the sake of this example's readability)
Also see this answer: https://stackoverflow.com/a/2390670/694576
Waiting for a condition should be preceded by a while statement, like this:
pthread_mutex_lock(mutex);
while(!conditionSatisfied)
pthread_cond_wait(condition, mutex);
pthread_mutex_unlock(mutex);
while signaling should be done in the following way:
pthread_mutex_lock(mutex);
conditionSatisfied = true;
pthread_cond_signal(condition);
pthread_mutex_unlock(mutex);
yes, mutex have to be locked before pthread_cond_wait, but doesn't have to for pthread_cond_signal. If you look back at your code, you see that the mutex will be unlocked twice, which is a sign of error... it is also possible for the child to call unlock on a mutex which has been destroyed by the parent...
Btw sleeping doesn't guarantee that the parent will execute first. To ensure this you will need ... a condition variable...

Resources