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:
sem_wait
and sem_post
push(waitroom, id)
in clientsem_wait
with sem_post
and vice versaNow 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:
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:
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
.queue
immediately after acquiring it. Instead, you should only release it when you are finished with the queue operation.push(waitroom, id)
twice, the second call being immediately after the first call. This does not make sense.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.sem_wait
. For example, it is possible that the function fails due to being interrupted by a signal handler.printf
in a signal handler. See this link for more information.