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.
Related
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
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.
In my producer and consumer problem, I use sem_open() to initialize the semaphores. How could I test if sem_open() works in a correct way?
The program can be compiled, but when I run the program it does not print anything. I test the program and found the problem maybe about sem_open(). I find if I comment the sem_open() in the program, the program will run correctly.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
pthread_t pro_thread, con_thread;
pthread_mutex_t mutex;
int counter = 0;
sem_t *empty, *full;
void print_buffer(int counter) {
for (int i = 0; i < counter; i ++)
{
printf("*");
}
printf("\n");
}
void* producer(void* var) {
int item;
while(1) {
item = rand() % 100 + 1;
sem_wait(empty);
pthread_mutex_lock(&mutex);
while (counter == BUFFER_SIZE)
; // waiting
if(counter < BUFFER_SIZE) {
buffer[counter] = item;
counter ++;
printf("Producer: ");
print_buffer(counter);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sem_post(full);
}
}
void* consumer(void* var) {
int item;
while(1) {
sem_wait(full);
pthread_mutex_lock(&mutex);
while (counter == 0)
; // waiting
if(counter > 0) {
counter --;
print_buffer(counter);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sem_post(empty);
}
}
int main(int argc, char *argv[]) {
pthread_mutex_init(&mutex, NULL);
empty = sem_open("/mysem", O_CREAT, 0644, BUFFER_SIZE);
full = sem_open("/mysem", O_CREAT, 0644, 0);
pthread_create(&pro_thread, NULL, producer, NULL);
pthread_create(&con_thread, NULL, consumer, NULL);
pthread_exit(NULL);
return 0;
}
As stated in the sem_open man page:
The semaphore is identified by name.
Since your code provides the same name value (/mysem) for both sem_open calls it results in referencing the same semaphore for both full and empty. That's clearly not what the logic of the program should be. Instead, open different semaphores for each. It's also best practice to check the return values of all function calls.
empty = sem_open("/empty_sem", O_CREAT, 0644, BUFFER_SIZE);
if (empty == SEM_FAILED) {
perror("Failed to open semphore for empty");
exit(-1);
}
full = sem_open("/full_sem", O_CREAT, 0644, 0);
if (full == SEM_FAILED) {
sem_close(empty);
perror("Failed to open semphore for full");
exit(-1);
}
I am trying to implement threading, a binary semaphore, and message queues in a client and server program. Everything works, except for the reply in my server to send a response back to the client. When I uncomment the reply, the server loops infinitely after receiving a message.
They both use a message.h header file that is a struct containing:
contents (character), id(int), and mtype(int).
// server.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include "message.h"
int sqid, cqid, pid;
msg m, n;
sem_t sem_var;
key_t key;
void requestSem();
void setSem();
void unlockSem();
void reply();
void readQueue();
void listener(void *ptr);
int main() {
key = ftok(".", 'z');
sqid = msgget(key, IPC_CREAT | 0600);
if(sqid < 0) {
perror("Error creating the message queue.\n");
}
pthread_t thread1;
pthread_t thread2;
pthread_t thread3;
char *msg1 = "Thread 1";
char *msg2 = "Thread 2";
char *msg3 = "Thread 3";
pthread_create(&thread1, NULL, (void *) &listener, (void *) msg1);
pthread_create(&thread2, NULL, (void *) &listener, (void *) msg2);
pthread_create(&thread3, NULL, (void *) &listener, (void *) msg3);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
}
// always listen for messages
void listener(void *ptr) {
while (1) {
requestSem();
setSem();
readQueue();
unlockSem();
//reply();
}
}
void readQueue()
{
// print the proccess ID and thread ID
printf("Process ID: %d, Thread ID: %d\n", getpid(), pthread_self());
// receive message
if(msgrcv(sqid,&m,sizeof(struct msg),0,0) < 0) {
perror("Error receiving a message.\n");
}
printf("Message was received...\n");
fprintf(stderr, "The contents are: %s\n", &m.contents);
fprintf(stderr, "The client's ID is: %d\n", (&m)->id);
fprintf(stderr, "The thread's ID is: %d\n", pthread_self());
}
void requestSem()
{
// request semaphore (lock)
sem_init(&sem_var, 1, 1);
printf("Semaphore requested.\n");
}
void setSem()
{
// lock semaphore
sem_wait(&sem_var);
printf("Semaphore set.\n");
}
void unlockSem()
{
// unlock semaphore
sem_post(&sem_var);
printf("Semaphore unlocked.\n");
}
void reply()
{
// send reply
printf("got here\n");
pid = (&m)->id;
cqid = msgget(pid, 0600);
n.contents = (&m)->contents;
n.mtype = 0;
n.id = getpid();
if(msgsnd(cqid, &n,sizeof(struct msg),0) < 0) {
perror("Msg send error");
}
msgctl(sqid,IPC_RMID,NULL);
}
// client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include "message.h"
int main() {
// initialize variables
int mqid, rqid;
msg m;
key_t key;
// initialize message
int pid;
pid = getpid();
m.id = pid;
m.mtype = 1;
// create message queue and response queue
key = ftok(".", 'z');
mqid = msgget(key, 0600);
rqid = msgget(pid, IPC_CREAT | 0600);
if(mqid < 0) {
perror("Error creating the message queue.\n");
}
if (rqid < 0)
{
perror("Error creating the message queue.\n");
}
// loop forever, can send as many messages as you want
while(1) {
fprintf(stderr, "The ID of the client is: %d\n", pid);
// prompt for user input
printf("Enter one character to send: \n");
scanf("%s", &m.contents);
// send message
if(msgsnd(mqid, &m,sizeof(struct msg), 1) < 0) {
perror("Error sending the message.");
}
//msgctl(mqid,IPC_RMID,NULL);
printf("Message was sent successfully!\n");
// receive response
printf("Waiting for a reply...\n");
if(msgrcv(rqid,&m,sizeof(msg), 0, 0) < 0)
{
perror("Error receiving a message.\n");
}
printf("Message was received.\n");
fprintf(stderr, "The contents are: %s\n", &m.contents);
}
}
Thank you in advance for any help. Everything functions as it's supposed to when reply is commented out within listener in the server. Uncommenting it creates an infinite loop.
the reason the server never exits is because each thread has a
while(1)
loop and no way to exit that loop
what I want is this:
1 main process that create 4 children process where:
-> The main process receive messages from the children through the queue and print the message recieved.
-> The children send messages (a string with priority+message) through the queue and finish.
All in a while (1), so, when you CTRL+C, the children finish first (the signal is in the children code) and then, the parent finish.
For the moment, I am having problem with mq_send() and mq_recieve().
Well, this is my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
void sigint_handler()
{
/*do something*/
printf("killing process %d\n",getpid());
exit(0);
}
int main ()
{
mqd_t mqd;
struct mq_attr atributos;
// atributos.mq_maxmsg = 10;
//
// atributos.mq_msgsize = 50;
printf ("This is the parent. PID=%d\n",getpid ());
int num_children = 4;
int i;
int pid;
int status;
char buffer [50];
while (1){
for (i=0; i<num_children ;i++){
if ((pid=fork()==0)){
signal(SIGINT, sigint_handler);
int prio = rand () % 3;
printf ("%d\n",prio);
char * msg= "Hi dude";
char * priority=NULL;
if (prio == 0){
priority = "NORMAL";
}
else {
priority = "URGENT";
}
char* toSend=NULL;
toSend = malloc(strlen(msg)+1+strlen(priority));
strcpy (toSend,priority);
strcat (toSend,msg);
printf ("%s\n",toSend);
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
if (mq_send(mqd, msg , strlen(toSend), prio) == -1) {
printf ("Error mq_send\n");
exit (-1);
}
mq_close(mqd);
printf ("This is children %d\n",getpid());
sleep(1);
exit(0);
}
}
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
//Rest Parent code
if (mq_receive(mqd, buffer, strlen(buffer),0)==-1){
printf ("Error mq_recieve\n");
exit(-1);
}
printf("Received: %s\n",buffer);
sleep (1);
waitpid(pid,&status,0);
printf ("This is the parent again %d, children should have finished\n",getpid());
mq_close(mqd);
}
}
I don't know why both mq_send() and mq_receive() returns -1, what am I doing wrong¿?
And you you see something wrong in my code in order to do what I intend apart from the error I am talking about, let me know.
Thank you in advance, I appreciate any help.
user58697 touched upon the biggest problems.
(1) Your queue opens were failing with EINVAL because you wee passing uninitialized attributes because you commented out assignments.
(2) You were opening both queues for write-only. The parent queue needed to be opened in read mode.
(3) Execute permissions don't mean anything to a queue so 777 permissions while not invalid are unnecessary.
(4) Your sends/receives were failing because of invalid lengths. In many if not most cases it is just easier and safer to allocate your buffers to the length attribute of the queue. In this case you know the length before hand but in programs that don't you can get the value via mq_getattr.
(5) You weren't calling srand to seed the RNG before calling rand.
(6) You had a memory leak where you allocate space (unnecessarily) for the message but never freed it.
(7) What you were trying to do with passing priorities is redundant. POSIX MQs have priorities already built in. You can just use those.
I took out some of the fluff (mainly the loops & signals) to concentrate more on the queue aspects of your program.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
int main()
{
srand(time(NULL));
mqd_t mqd;
struct mq_attr atributos = {.mq_maxmsg = 10, .mq_msgsize = 50};
int i;
int pid;
int status;
int num_children = 4;
char buffer[atributos.mq_msgsize];
for (i = 0; i < num_children; i++)
{
if ((pid = fork() == 0))
{
int prio = rand () % 3;
char* msg = "Hi dude";
strncpy (buffer, msg, sizeof(buffer));
if ((mqd = mq_open("/queue.txt", O_CREAT | O_WRONLY, 0666, &atributos)) == -1)
{
perror("child mq_open");
exit(1);
}
if (mq_send(mqd, buffer, sizeof(buffer), prio) == -1)
{
perror("mq_send");
exit(1);
}
mq_close(mqd);
exit(0);
}
}
// parent
if ((mqd = mq_open("/queue.txt", O_CREAT | O_RDONLY, 0666, &atributos)) == -1)
{
perror("parent mq_open");
exit(1);
}
int priority;
for (int i = 0; i < num_children; ++i)
{
if (mq_receive(mqd, buffer, sizeof(buffer), &priority) == -1)
{
perror("mq_recieve");
exit(1);
}
printf("Received (%s): %s\n", (priority == 0) ? "NORMAL" : "URGENT", buffer);
pid_t childpid;
if ((childpid = waitpid(-1, &status, 0)) > 0)
{
if (WIFEXITED(status))
printf("PID %d exited normally. Exit status: %d\n",
childpid, WEXITSTATUS(status));
else
if (WIFSTOPPED(status))
printf("PID %d was stopped by %d\n",
childpid, WSTOPSIG(status));
else
if (WIFSIGNALED(status))
printf("PID %d exited due to signal %d\n.",
childpid,
WTERMSIG(status));
}
}
mq_close(mqd);
}
First and foremost, when a system call fails, print errno (and strerror(errno)).
Now, obvious mistakes:
as was mentioned, you need a read access to be able to mq_receive()
what is strlen(buffer)?
you are passing attributes without initializing them.
To summarize, print errno and see what is wrong.