Related
few days ago I started working on the sleeping barber problem, got some issues with segmentation fault But they have been solved here
Even though I fixed the missing parts, I still have a problem. I need to use FIFO queue, and create shared memory for it. I get no errors when creating it. Running the client should let me put clientAmount of clients into the queue, from which barber should be getting them. Every client is described by his process id. But when I try to do so, client program shows that clients have been added to queue:
2101 entered the queue
2099 entered the queue
2104 entered the queue
2097 entered the queue
2103 entered the queue
2095 entered the queue
2102 entered the queue
2098 entered the queue
2096 entered the queue
but when I run the barber code, all I get is:
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
Queue empty, I fall asleep
I'm waking up
I'm not really sure what to do here.
The code for client:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
int numberOfCuts;
int isCut;
int isDone;
void status(int f);
int main(int argc,char* argv[])
{
if(argc < 3){
printf("Error while executing program, invalid amount of arguments");
return 0;
}
sem_t *barber;
sem_t *queue;
sem_t *client;
sem_t *pillow;
int clientsAmount;
int sharedmem, waitRoomSize;
struct Queue* waitroom;
void *space;
int i;
signal(SIGUSR1, status);
clientsAmount = atoi(argv[1]);
numberOfCuts = atoi(argv[4]);
barber = sem_open("/B", O_RDWR);
if((barber == SEM_FAILED)){
perror("Error while getting semaphore for barber");
exit(1);
}
queue = sem_open("/Q", O_RDWR);
if((queue == SEM_FAILED)) {
perror("Error while creating semaphore for queue");
exit(1);
}
client = sem_open("/C", O_RDWR);
if(client == SEM_FAILED){
perror("Error while creating semaphore for pillow");
exit(0);
}
sharedmem = shm_open("QueueMem", O_RDWR, 0666);
if(sharedmem==-1){
perror("Error while getting shared memory");
exit(1);
}
space = mmap(NULL, sizeof(waitroom), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
if((space == MAP_FAILED)){
perror("Error while mapping memory");
exit(1);
}
waitroom = (struct Queue*) space;
for(i = 0; i< clientsAmount; i++){
if(fork() == 0){
int isCut = 0;
int id = getpid();
printf("%d entered the queue \n", id);
sem_wait(queue);
sem_post(queue);
if( push(waitroom, id)==-1){
printf("Queue is full, leaving...");
exit(0);
}else {
push(waitroom, id);
sem_wait(pillow);
printf("%d: Barber is sleeping, he needs to wake up", id);
int x;
sem_getvalue(barber, &x);
if(x==0){
sem_post(barber);
while(x!= 0){
sem_post(barber);
printf("Barber is waking up to cut %d", id);
}
}
sem_post(pillow);
_exit(0);
}
}
}
sem_close(barber);
sem_unlink("/B");
sem_close(queue);
sem_unlink("/Q");
sem_close(client);
sem_unlink("/C");
}
void status(int f){
numberOfCuts--;
printf("Remaining cuts: %d", numberOfCuts);
isCut = 1;
while(!numberOfCuts)
{
printf("Leaving the barber");
isDone =1;
}
}
The barber code:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
#define BARBER "Barber"
int main(int argc,char* argv[])
{
if(argc < 2){
printf("Error while executing program, invalid amount of arguments");
return 0;
}
sem_t *barber;
sem_t *queue;
sem_t *client;
int seats;
int sharedmem, waitRoomSize;
struct Queue* waitroom;
queue = sem_open("/Q", O_CREAT | O_RDWR, 0666, 1);
if((queue == SEM_FAILED)) {
printf("Error while creating semaphore for queue");
exit(1);
}
barber= sem_open("/B", O_CREAT | O_RDWR, 0666, 1);
if((barber == SEM_FAILED)){
printf("Error while creating semaphore for barber");
exit(1);
}
client = sem_open("/C", O_CREAT | O_RDWR, 0666, 0);
if(client == SEM_FAILED){
printf("Error while creating semaphore for pillow");
exit(0);
}
seats = atoi(argv[1]);
void *space;
sharedmem = shm_open("Queue",O_CREAT | O_RDWR, 0666);
if(sharedmem==-1){
printf("Error while getting shared memory");
exit(1);
}
waitRoomSize = ftruncate(sharedmem, sizeof(waitroom));
if((waitRoomSize ==-1)){
printf("Error while getting size");
exit(1);
}
space = mmap(NULL, sizeof(struct Queue), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
if((space == MAP_FAILED)){
printf("Bład podczas mapowania pamiêci");
exit(1);
}
waitroom = (struct Queue*) space;
queueinit(waitroom, seats);
printf("semaphores created\n");
while(1)
{
sem_post(queue);
int x = isEmpty(waitroom);
sem_wait(queue);
if(x==1){
printf("Queue empty, I fall asleep\n");
sem_post(barber);
sem_wait(barber);
printf("I'm waking up\n");
} else {
sem_post(queue);
int id = get(waitroom);
sem_wait(queue);
printf("%d, please sit on the chair\n", id);
printf("Started cutting hair for %d\n", id);
sleep(2);
printf("Cutting done for :%d \n", id);
kill(id, SIGUSR1);
}
}
sem_close(barber);
sem_unlink("/B");
sem_close(queue);
sem_unlink("/Q");
sem_close(client);
sem_unlink("/C");
printf("senaphores unlinked");
}
The code for queue:
#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
struct Queue{
int elems[500];
int size;
int queueIn;
int queueOut;
int isAsleep;
int mainPID;
int countCurrent;
};
void queueinit(struct Queue* q, int size){
q->size = size;
q->queueIn = q->queueOut = 0;
q->isAsleep = 0;
q->countCurrent = 0;
}
int push(struct Queue* q, int e){
if(q->queueIn == ((q->queueOut -1 + q->size) % q->size)){
return -1; //Queue full
}
q->elems[q->queueIn] = e;
q->queueIn = (q->queueIn + 1) % q->size;
return 0;
}
int get(struct Queue* q){
int e = q->elems[q->queueOut];
q->queueOut = (q->queueOut + 1) % q->size;
return e;
}
int isEmpty(struct Queue* q){
if(q->queueIn == q->queueOut)
return 1;
return 0;
}
void lock(sem_t* sem){
if(sem_wait(sem) == -1){
printf("Error while lockin semaphore");
exit(1);
}
}
void free_sem(sem_t* sem){
if(sem_post(sem) == -1){
printf("Error while releasing semaphore");
exit(1);
}
}
#endif // FUNCTIONS_H_INCLUDED
Any suggestion would be greatly appreciated
EDIT
As of now, few changed have been added:
Checking the return value of sem_wait and sem_post
Removed the second call for push(waitroom, id) in client
Took care of locking and unlocking semaphores, mainly swapped sem_wait with sem_post and vice versa
Got rid of the pillow semaphore
Now the program was working nearly fine, however the client code did not exit after all its children finished their work. Pressing [ENTER] works. So I took the given advice and created a new semaphore - p, which I lock instead of using pause() in client code, and I unlock it in signal handler status(). I also cahnged the value with which barber semaphore was initialized - no more double locking or freeing a semaphore.
I also tried to use abort() function instead of exit but it didn't work.
What happens now:
Barber code does start but nothing happens.
Client code starts and adds some values to queue, and immediately exits.
The updated code for barber:
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
#define BARBER "Barber"
int main(int argc,char* argv[])
{
if(argc < 2){
printf("Error while executing program, invalid amount of arguments");
return 0;
}
sem_t *barber;
sem_t *queue;
sem_t *p;
int seats;
int sharedmem, waitRoomSize;
struct Queue* waitroom;
queue = sem_open("/Q", O_CREAT | O_RDWR, 0666, 1);
if((queue == SEM_FAILED)) {
printf("Error while creating semaphore for queue");
exit(1);
}
barber= sem_open("/B", O_CREAT | O_RDWR, 0666, 0);
if((barber == SEM_FAILED)){
printf("Error while creating semaphore for barber");
exit(1);
}
p= sem_open("/P", O_CREAT | O_RDWR, 0666, 0);
if((p == SEM_FAILED)){
printf("Error while creating semaphore for barber");
exit(1);
}
seats = atoi(argv[1]);
void *space;
sharedmem = shm_open("QueueMem",O_CREAT | O_RDWR, 0666);
if(sharedmem==-1){
printf("Error while getting shared memory");
exit(1);
}
waitRoomSize = ftruncate(sharedmem, sizeof(waitroom));
if((waitRoomSize ==-1)){
printf("Error while getting size");
exit(1);
}
space = mmap(NULL, sizeof(struct Queue), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
if((space == MAP_FAILED)){
printf("Error while mapping memory");
exit(1);
}
waitroom = (struct Queue*) space;
queueinit(waitroom, seats);
while(1)
{
lock(queue);
if(isEmpty(waitroom)==1){
printf("Queue empty, I fall asleep\n");
waitroom->isAsleep = 1;
free_sem(queue);
lock(barber);
printf("I'm waking up\n");
} else {
int id = get(waitroom);
free_sem(queue);
printf("%d, please sit on the chair\n", id);
printf("Started cutting hair for %d\n", id);
sleep(2);
printf("Cutting done for :%d \n", id);
kill(id, SIGUSR1);
}
}
sem_close(barber);
sem_unlink("/B");
sem_close(queue);
sem_unlink("/Q");
sem_close(p);
sem_unlink("/P");
//exit(0);
//printf("senaphores unlinked");
}
The updated code for client:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "functions.h"
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
int numberOfCuts;
#include "functions.h"
int id;
sem_t *barber;
sem_t *queue;
sem_t *p;
int clientsAmount;
int sharedmem, waitRoomSize;
struct Queue* waitroom;
void *space;
void status(int f);
void handler(int f);
int main(int argc,char* argv[])
{
if(argc < 3){
printf("Error while executing program, invalid amount of arguments");
return 0;
}
int i;
signal(SIGUSR1, status);
signal(SIGINT, handler);
int pid = getpid();
clientsAmount = atoi(argv[1]);
numberOfCuts = atoi(argv[2]);
barber = sem_open("/B", O_RDWR);
if((barber == SEM_FAILED)){
perror("Error while getting semaphore for barber");
exit(1);
}
queue = sem_open("/Q", O_RDWR);
if((queue == SEM_FAILED)) {
perror("Error while creating semaphore for queue");
exit(1);
}
p = sem_open("/P", O_RDWR);
if((p == SEM_FAILED)) {
perror("Error while creating semaphore for queue");
exit(1);
}
sharedmem = shm_open("QueueMem", O_RDWR, 0666);
if(sharedmem==-1){
perror("Error while getting shared memory");
exit(1);
}
space = mmap(NULL, sizeof(waitroom), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
if((space == MAP_FAILED)){
perror("Error while mapping memory");
exit(1);
}
waitroom = (struct Queue*) space;
for(i = 0; i< clientsAmount; i++) {
if(fork() == 0) {
id = getpid();
printf("%d entered the barbershop \n", id);
while(1) {
lock(queue);
if( push(waitroom, id)==-1 ) {
free_sem(queue);
printf("Queue is full, %d leaving...\n", id);
exit(0);
} else {
free_sem(queue);
printf("%d has entered the queue \n", id);
lock(queue);
int x;
x = waitroom->isAsleep;
if(x==1){
printf("%d: Barber is sleeping, he needs to wake up\n", id);
waitroom->isAsleep = 0;
free_sem(queue);
free_sem(barber);
printf("Barber is waking up to cut %d\n", id);
} else {
printf("Barber is cutting someone else, %d waiting for its turn", id);
free_sem(queue);
}
}
lock(p);
}
break;
}
}
//exit(0);
sem_close(barber);
sem_close(queue);
sem_close(p);
munmap(space, waitRoomSize);
exit(0);
}
void handler(int f) {
printf("Closing");
sem_close(barber);
sem_close(queue);
munmap(space, waitRoomSize);
exit(0);
}
void status(int f) {
numberOfCuts--;
free_sem(p);
printf("Remaining cuts for %d: %d\n", id, numberOfCuts);
if(!numberOfCuts) {
printf("%d is done cutting \n", id);
exit(0);
}
}
There are several mistakes in your program:
In the client code, you are calling sem_wait(pillow) and sem_post(pillow);, although the variable pillow has not been initialized. This causes undefined behavior. In order to initialize a semaphore, you can use the functions sem_init or sem_open.
In the client code, you release the mutex queue immediately after acquiring it. Instead, you should only release it when you are finished with the queue operation.
In the client code, you call push(waitroom, id) twice, the second call being immediately after the first call. This does not make sense.
In the barber's main loop, you are releasing the mutexes queue and barber without acquiring them beforehand, then acquire them afterwards. A mutex should normally first be acquired, then released, not the other way around. Use sem_wait for acquiring the mutex, sem_post for releasing it. EDIT: Meanwhile, I believe that you are using the semaphore barber for signalling purposes, not as a mutex. In that case, it is correct to call sem_post without having called sem_wait beforehand.
You are not checking the return value of sem_wait. For example, it is possible that the function fails due to being interrupted by a signal handler.
It is not safe to use the function printf in a signal handler. See this link for more information.
You are not waiting for the child processes to finish, before terminating the parent process.
I'm trying to implement producer-consumer problem in C using processes and System V IPC and I'm stuck on one thing. This is early version of my code (without implementing queue operations or even producer and consumer executing in loop) that I was using to learn and test how semaphores work:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <time.h>
#include "sem.h"
#include "shm.h"
#define BUFFER_SIZE 9
int full;
int empty;
int mutex;
struct buff {
int queue[BUFFER_SIZE];
} *buffer;
void producer();
void consumer();
int main() {
int parent_pid, pid, i;
parent_pid = getpid();
int shmid = allocate_shared_memory(sizeof(*buffer));
buffer = (struct buff *) attach_shared_memory(shmid);
for (i = 0; i < BUFFER_SIZE; i++) {
buffer->queue[i] = 0;
}
full = sem_allocate();
empty = sem_allocate();
mutex = sem_allocate();
printf("Full %d\n", full);
printf("Empty %d\n", empty);
printf("Mutex %d\n", mutex);
sem_init(full, 0);
sem_init(empty, BUFFER_SIZE);
sem_init(mutex, 1);
printf("Full value %d\n", sem_get_val(full));
printf("Empty value %d\n", sem_get_val(empty));
printf("Mutex value %d\n", sem_get_val(mutex));
srand(time(0));
pid = fork();
if (!pid) {
printf("Producer here: %d\n", getpid());
producer();
printf("Full value after prod() %d\n", sem_get_val(full));
return 0;
} else printf("Created new producent: %d\n", pid);
sleep(1);
pid = fork();
if (!pid) {
printf("Consumer here: %d\n", getpid());
printf("Full value before cons() %d\n", sem_get_val(full)); //here I always get 0
consumer();
return 0;
} else printf("Created new consumer: %d\n", pid);
while (1)
{
int status;
pid_t done = wait(&status);
if (done == -1)
{
if (errno == ECHILD) break; // no more child processes
}
else
{
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
exit(1);
}
}
}
if (getpid() == parent_pid) {
sem_deallocate(full);
sem_deallocate(empty);
sem_deallocate(mutex);
}
}
void producer() {
sem_wait(empty);
sem_wait(mutex);
printf("Producer is producing!\n");
buffer->queue[0]=0;
sem_post(mutex);
sem_post(full);
}
void consumer() {
sem_wait(full);
sem_wait(mutex);
printf("Consumer is consuming!\n");
sem_post(mutex);
sem_post(empty);
}
int sem_allocate() {
return semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
}
void sem_deallocate(int semid) {
if (semctl(semid, 0, IPC_RMID, NULL) == -1)
{
perror("Error releasing semaphore!\n");
exit(EXIT_FAILURE);
}
}
int sem_init(int semid, int value) {
union semun arg;
arg.val = value;
if (semctl(semid, 0, SETVAL, arg) == -1) {
perror("semctl");
return -1;
}else return 1;
}
int sem_wait(int semid) {
printf("Someone is waiting %d\n", semid);
struct sembuf sem = { 0, -1, SEM_UNDO };
return semop(semid, &sem, 1);
}
int sem_post(int semid) {
printf("Someone is posting %d\n", semid);
struct sembuf sem = { 0, 1, SEM_UNDO };
return semop(semid, &sem, 1);
}
int sem_get_val(int semid) {
return semctl(semid, 0, GETVAL, 0);
}
int allocate_shared_memory(int size) {
return shmget(IPC_PRIVATE, size, IPC_CREAT | SHM_W | SHM_R);
}
void deallocate_shared_memory(const void* addr, int shmid) {
shmctl(shmid, IPC_RMID, 0);
}
void* attach_shared_memory(int shmid) {
return shmat(shmid, NULL, 0);
}
sem.h:
#include <sys/types.h>
#include <errno.h>
union semun {
int val;
struct semid_ds *buf;
ushort* array;
};
int sem_post(int);
int sem_wait(int);
int sem_allocate();
void sem_deallocate(int);
int sem_init(int, int);
int sem_get_val(int);
shm.h:
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int allocate_shared_memory(int size);
void deallocate_shared_memory(const void* addr, int shmid);
void* attach_shared_memory(int shmid);
Why before executing consumer function value of full semaphore is 0? Even if right after producer finishes his job the value is 1...
I'm new to this kind of topics so maybe there is an obvious explenation of the situation, but I have no idea what can I do and hope you can help me.
You initialize the "full" semaphore to zero. Your "child" producer, prior to exiting calls your sem_post() function, which calls semop() with a SEM_UNDO argument.
int sem_post(int semid) {
printf("Someone is posting %d\n", semid);
struct sembuf sem = { 0, 1, SEM_UNDO };
return semop(semid, &sem, 1);
}
The Ubuntu Linux man page for semop says the following about SEM_UNDO:
... If an operation specifies SEM_UNDO, it will be automatically
undone when the process terminates.
This means, "producer" increments "full" prior to exiting, then after it exits the system "undoes" the increment (i.e. it decrements "full") setting it back to zero.
So,for the purposes of the "full" semaphore, you should NOT specify SEM_UNDO.
The program should create 200000 integers and write 2000 to a shared memory. A forked process should read 2000 from shared memory and the parent should write the next 2000 to shared memory.
if i use the code below without sleep, the parent first creates all 200000 integers and then the child reads the same integers from shared memory.
With sleep everything looks good, but we have to use semaphore.
shm.c (parent):
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <sys/wait.h>
#define N_DATA 200000
#define N_SHARED 2000
#define LOCK -1
#define UNLOCK 1
static struct sembuf semaphore;
char shmidArg[32];
char semidArg[32];
int *shmData;
int i, j;
int status;
char *strsignal(int sig);
pid_t pid;
static int shmid;
static int semid;
char *strsignal(int sig);
/** Semaphore Operation */
static int semaphore_operation (int op) {
semaphore.sem_num = 1;
semaphore.sem_op = op;
semaphore.sem_flg = IPC_NOWAIT;
if( semop (semid, &semaphore, 1) == -1) {
perror(" semop ");
exit (EXIT_FAILURE);
}
return 1;
}
int main(int argc, char **argv) {
/* Ein Shared-Memory-Segment einrichten */
shmid = shmget(IPC_PRIVATE, N_SHARED*sizeof(int), IPC_CREAT | SHM_R | SHM_W);
if (shmid == -1) {
perror("shmid");
exit(1);
}
printf("Shared-Memory-ID: %d\n",shmid);
/* Pointer zu Shared-Memory-Segment erhalten */
shmData = (int *)shmat(shmid,0, 0);
if (shmData == (int *)(-1)) {
perror("shmat");
exit(1);
}
/* Semaphore anlegen */
semid = semget(IPC_PRIVATE, 1, IPC_CREAT | SHM_R | SHM_W);
if (semid < 0) {
perror("semid");
exit(1);
}
printf ("Semaphor-ID : %d\n", semid);
/* Semaphor mit 1 initialisieren */
if (semctl (semid, 0, SETVAL, (int) 1) == -1) {
perror("semctl");
}
snprintf(shmidArg,32, "%d", shmid);
snprintf(semidArg,32, "%d", semid);
/** erstellen des Kindprozesses */
pid = fork();
// Kindprozess
if (pid == 0) {
execlp("./shm_child",shmidArg,semidArg,NULL);
} else if (pid < 0) {
perror("Kindprozess konnte nicht erzeugt werden!");
return 1;
}
// Elternprozess
else {
/** ininitalisieren des Zufallsgenerator durch aktuellen Zeitstempel */
srand48(time(NULL));
for(i=0;i<N_DATA;i=i+N_SHARED) {
semaphore_operation(LOCK);
for (j=0; j<N_SHARED; j++) {
shmData[j] = lrand48();
//MSZ
//printf("SHM-->%d-->%d\n",i+1,shmData[i]);
}
// if(i == 0 || i == 2000) {
printf("Parent-->%d-->0-->%d\n",i,shmData[0]);
printf("Parent-->%d-->1999->%d\n",i,shmData[1999]);
// }
semaphore_operation(UNLOCK);
//sleep(1);
}
}
//MSZ
//sleep(2);
printf("PID: %d\n", pid);
if (waitpid(pid, &status, 0) == -1) {
perror("wait konnte nicht erzeugt werden!");
return 1;
}
if (WIFEXITED(status)) {
printf("Exitcode: %d\n", WEXITSTATUS(status));
semctl (semid, 0, IPC_RMID, 0);
shmctl (shmid, IPC_RMID, NULL);
//If process terminaded by a signal
} else if (WIFSIGNALED(status)) {
printf("Signal: %d %s\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
semctl (semid, 0, IPC_RMID, 0);
shmctl (shmid, IPC_RMID, NULL);
}
}
shm_child.c (Child):
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#define N_DATA 6000
#define N_SHARED 2000
#define LOCK -1
#define UNLOCK 1
int i,j;
int *shmData;
static int shmid;
static int semid;
static struct sembuf semaphore;
/** Semaphore Operation */
static int semaphore_operation (int op) {
semaphore.sem_num = 0;
semaphore.sem_op = op;
semaphore.sem_flg = SEM_UNDO;
if( semop (semid, &semaphore, 1) == -1) {
perror(" semop ");
exit (EXIT_FAILURE);
}
return 1;
}
int main(int argc, char **argv) {
shmid = atoi(argv[0]);
semid = atoi(argv[1]);
printf("\nshm_child shared memoryid:%d\n",shmid);
printf("shm_child Semaphoren-ID:%d\n",semid);
/* Pointer auf Shared-Memory erstellen */
shmData = (int *)shmat(shmid,0,0);
if (shmData == (int *)(-1)) {
perror("shmat");
exit(1);
}
for(i=0;i<N_DATA;i=i+N_SHARED) {
semaphore_operation(LOCK);
for(j=0;j<N_SHARED;j++) {
//printf("%d-->%d --> %d\n",i,j+1,shmData[j]);
}
// if(i == 0 || i == 2000) {
printf("child-->%d-->0-->%d\n",i,shmData[0]);
printf("child-->%d-->1999->%d\n",i,shmData[1999]);
// }
semaphore_operation(UNLOCK);
sleep(1);
}
return 0;
}
Please help us
Thank you guys
Edit: Thank you very much for your answers. I can't mark the right answer because i dont know what its right. But i dont want try anything more. 15 hours are enough
The writer process shall give reader a permission to read, and wait for the reading completion. After that the reader shall give writer a permission to proceed, and wait for writing completion.
This goal cannot be achieved with a single semaphore. You need two, along the lines of:
// parent aka writer
writer_barrier = semaphore(UNLOCKED);
reader_barrier = semaphore(LOCKED);
start_reader();
while(...) {
lock(writer_barrier);
write_data();
unlock(reader_barrier);
}
// child aka reader
while(....)
lock(reader_barrier);
read_data();
unlock(writer_barrier);
}
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;
}
I have the following code which works fine with the sleep time. But I want to remove sleep and use semaphores to synchronize the threads ( so that the reader waits till data is available in shmptr.) How do I do that? What do I use:
sem_t mutex or
pthread_mutex_t mutex?
P.S : I tried using both above options separately (not shown in above code though) but didn't get desired result.Most of the times I was getting error in shmget in reader - "shmget in reader: No such file or directory".
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <semaphore.h>
#include <errno.h>
void *write(void *t)
{ char str[100] = "\0";
char str1[50];
key_t key;
char *shmptr;
int shmid;
if( (key = ftok("shmSemphore.c",'B')) == -1)
{
perror("ftok in writer");
pthread_exit(NULL);
}
if( (shmid = shmget(key, 1024, 0666 | IPC_CREAT)) == -1)
{
perror("shmget in writer");
pthread_exit(NULL);
}
shmptr = shmat(shmid,0,0);
if( (shmptr == (char *)(-1)))
{
perror("shmget in writer");
pthread_exit(NULL);
}
printf("ENter your text :- ");
//scanf("%s",str);
fgets(str,sizeof(str),stdin);
strcpy(shmptr,str);
sleep(2);
shmdt(shmptr);
if( shmctl(shmid, IPC_RMID, NULL) == -1 )
{
perror("shmctl");
exit(-1);
}
pthread_exit(NULL);
}
void *read(void *t)
{ sleep(2);
key_t key;
char *shmptr;
int shmid;
if( (key = ftok("shmSemphore.c",'B')) == -1)
{
perror("ftok in writer");
pthread_exit(NULL);
}
if( (shmid = shmget(key, 1024, 0)) == -1)
{
perror("shmget in reader");
pthread_exit(NULL);
}
shmptr = shmat(shmid,0,0);
if( (shmptr == (char *)-1))
{
perror("shmget in writer");
pthread_exit(NULL);
}
printf("your text:- %s \n",shmptr);
pthread_exit(NULL);
}
int main()
{
pthread_t reader,writer;
int rt;
long t = 0;
rt = pthread_create(&writer,NULL,write,(void *)t);
/*if(rt == -1)
{ perror("writer thread");
pthread_exit(NULL);
}*/
rt = pthread_create(&reader,NULL,read,(void *)t);
/*if(rt == -1)
{ perror("writer thread");
pthread_exit(NULL);
}*/
pthread_join(writer,NULL);
pthread_join(reader,NULL);
return 0;
}