So I'm doing the barbershop problem but now I want to make it 'visual' and network-friendly. When the server starts up, awaits for clients to connect, each time a client connects it draws a 'P' that travels around the screen up to the barber position. I do this with NCurses and I have no problem with that.
However I only managed to draw one client (one 'P') at a time. I'd like to see many clients ('P's) in the screen. Because the way I have it now I only use 1 chair at a time, the client then gets attended and exits, then the next client in the accept() queue enters the screen and so on. It gives the impression that there is no actual concurrence thought there is.
I have a very extense code but the fork/socket part is here:
pid_t client;
int p;
RandSeed=8;
listen(connection,90);
while(1){
remote_dir_size = sizeof(remote_dir);
//"Awaiting connection...
if((connection_client=accept(connection,(struct sockaddr *)&remote_dir,&remote_dir_size))<0){
console_write("CONNECTION REJECTED!");
exit(-1);
}
//"Connection accepted!
client=fork();
switch(client)
{
case -1:
console_write("Error Forking!!");
exit(1);
case 0:
close(connection); //So that another client can come.
recvs = recv(connection_client,petition,sizeof(petition),0);
//console_write(petition);
// console_write(" moviendose.");
move_client();
//Check for avialable chairs
//waiting_client_count++;
sem_wait(waitingRoom); //wait until available
move_client_to_chairs();
sitting_client_count++;
redraw_chairs(); //redraw chair <--Useless since only 1 chair is used at a time :/
//waiting for barber
sem_wait(barberChair);
//barber available, chair occupied is now free
sem_post(waitingRoom);
sitting_client_count--;
redraw_chairs();
move_client_to_barber(); //Move 'P' towards barber chair
sit_client_barber();
//Wake barber
sem_post(barberPillow);
//Wait until barber ends
sem_wait(seatBelt);
//release chair
sem_post(barberChair);
exit_client();
exit(0);
default:
//barber sleeps until someone wakes him
sem_wait(barberPillow);
randwait(5);
//barber cutting hair
randwait(5);
//barber finished
//free client
sem_post(seatBelt);
wait(&p);
}
}
Complete version of the code is here
My problem is:
Server starts up good. Then when I run a ./client
the server screen starts drawing the P
along the screen and it moves it correctly, the client gets its haircut and exits. But when I run 2 or more ./client
s the server screen draws the process once at a time, there's only one client at a time inside the barbershop; as if it's waiting for that one client to exit()
in order to start the next fork
ed process.
I find this very odd, what am I missing here? Is it a problem of accept
queue? Should I try a different perspective?
The problem is that your parent process is trying to do two different things that need waiting:
"barber sleeps until someone wakes him"
accept()
Without some kind of joint waiting, this architecture does not work. Both pieces of code sleeps waiting for a single kind of event, disregarding the other type of event. For example, when a client comes in, the program will not accept another client until "barber finished".
There are two directions to solve the problem:
accept()
, you can turn the socket into non-blocking mode, and useselect()
orpoll()
to wait until an event comes in, for the semaphore, this is not so trivial, but if you open a socket between the parent and each child, and turn the semaphore handling into network communications, you can have a singleselect()
orpoll()
waiting for all the sockets (one for receiving new client connections, and one per client for communicating with them) at a single place. You'd also have to redesign the semaphore handling - and get rid of the sleep there, something like keeping a list of active timers, and go back toselect()
orpoll()
until the next timer times out (their last parameter can put a limit on the maximum wait time).accept()
and the semaphore handling into two processes, ie the parent is handling the new incoming connections, and a child process "simulates" the barber. Actually, the way you tried to implement the "barber", you'd need one child process per barber, because the process is sleeping while simulating the job done by the barber. Or you redesign the "barber" simulation as mentioned in the first part.