Dining Philosophers in C using fork() - c

I wrote a C program for the Dining Philosophers Problem using pthread some time ago and am now trying to change it to use fork() instead. This is an exercive for a lecture I already passed. But a friend asked me for help and I can't seem to get it figured out by myself, which is driving me crazy!
If i do a "ps" the processes are there. But there isn't any output to stdout, so I think I'm doing something wrong with the pipes.
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define N 5
#define LEFT (i+4)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATING 2
sem_t spoon;
sem_t phil[N];
int state[N];
int phil_num[N]={0,1,2,3,4};
int fd[N][2]; // file descriptors for pipes
pid_t pid, pids[N]; // process ids
int i;
int num;
void philosopher(int i);
void test(int i);
void take_spoon(int i);
void put_spoon(int i);
char buffer[100];
int main(void)
{
for(i=0;i<N;++i)
{
pipe(fd[i]);
pids[i] = fork();
printf("i=%d\n",i);
printf("pids[i]=%d\n",pids[i]);
if(pids[i]==0)
{
// child
dup2(fd[i][1],1);
close(fd[i][0]);
close(fd[i][1]);
philosopher(i);
_exit(0);
}
else if(pids[i]>0)
{
// parent
dup2(fd[i][0],0);
close(fd[i][0]);
close(fd[i][1]);
}
}
// wait for child processes to end
for(i=0;i<N;++i) waitpid(pids[i],NULL,0);
return 0;
}
void philosopher(int i)
{
while(1)
{
sleep(1);
take_spoon(i);
sleep(2);
put_spoon(i);
sleep(1);
}
}
void take_spoon(int i)
{
sem_wait(&spoon);
state[i] = HUNGRY;
printf("philosopher %d is hungry\n",i+1);
test(i);
sem_post(&spoon);
sem_wait(&phil[i]);
}
void put_spoon(int i)
{
sem_wait(&spoon);
state[i] = THINKING;
printf("philosopher %d puts down spoon %d and %d hin\n",i+1,LEFT+1,i+1);
printf("philosopher %d thinks\n",i+1);
test(LEFT);
test(RIGHT);
sem_post(&spoon);
}
void test(int i)
{
if( state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING)
{
state[i] = EATING;
printf("philosopher %d takes spoon %d and %d\n",i+1,LEFT+1,i+1);
printf("philosopher %d eats\n",i+1);
sem_post(&phil[i]);
}
}
Thank you in advance for any help.

Several issues. First is that after fork(), the child process and parent process do not share memory. This is one of the primary differences between a thread and a process. Each process has its own virtual address space. Whatever you want the philosophers to share, you have to explicitly do that by creating shared memory. It seems you intended your global variables to be shared among all the processes. (Note that there are some things shared, such as open file descriptors, and the child does get a copy of the variables from the parent, initialized to the values that were assigned to them at the time of the fork() call.)
Second, you have some confusingly unnecessary variables. In particular, the pipes do not serve any real purpose. The stdout for each of the processes will go to the console screen already, without the need for trying to pipe them back to the parent. This is because the child process already inherits the open file descriptors of the parent, so the child will already be using the same stdout as the parent. In addition, the phil_num, and num variables were unused, and the i. pid and pids variables seemed to be needlessly made global.
Third, you failed to initialize your semaphores. The default initialization as a global variable probably leaves the semaphore "useable" but with a 0 initial value, meaning sem_wait() on it will just block. In your case, you need those semaphores in shared memory, so a call to sem_init() is mandatory anyway (to indicate it is going to be shared between multiple processes), and the call gives you a chance to properly initialize the semaphore with a value of 1 so that the initial sem_wait() call has a chance to return.
After adjusting the globals down to what really needs to be shared, they can be bundled together into a structure. Then, a global pointer can be created for the shared data.
struct shared_data {
sem_t spoon;
sem_t phil[N];
int state[N];
};
struct shared_data *shared;
void initialize_shared(); /* at program start */
void finalize_shared(); /* at program end */
One way to create shared memory is to use mmap(). After the memory is created, the data should be initialized properly. This includes a call to sem_init() on the semaphores. sem_destroy() is used to clean up a semaphore, and the mapped memory can be released with munmap(). These are done for you when the process exits, but provided for completeness. (You should always check the return values of all the operating system calls you make, but I have elided them for the sake of brevity.)
void initialize_shared()
{
int i;
int prot=(PROT_READ|PROT_WRITE);
int flags=(MAP_SHARED|MAP_ANONYMOUS);
shared=mmap(0,sizeof(*shared),prot,flags,-1,0);
memset(shared,'\0',sizeof(*shared));
sem_init(&shared->spoon,1,1);
for(i=0;i<N;++i) sem_init(&shared->phil[i],1,1);
}
void finalize_shared()
{
int i;
for(i=0;i<N;++i) sem_destroy(&shared->phil[i]);
munmap(shared, sizeof(*shared));
}
Your main() implementation does not really change, except you need to add local variables for the ones that were needlessly global, as well as call initialize_shared() and optionally finalize_shared(). Also, remove all the code related to pipe().
int main(void)
{
int i;
pid_t pid, pids[N]; // process ids
initialize_shared();
for(i=0;i<N;++i)
{
pid = fork();
if(pid==0)
{
// child
philosopher(i);
_exit(0);
}
else if(pid>0)
{
// parent
pids[i] = pid;
printf("pids[%d]=%d\n",i,pids[i]);
}
else
{
perror("fork");
_exit(0);
}
}
// wait for child processes to end
for(i=0;i<N;++i) waitpid(pids[i],NULL,0);
finalize_shared();
return 0;
}
Note that your program never really exits on its own, since philosopher() is implemented as an infinite loop.

Related

Why my producer-consumer program in C not working properly?

I'm trying to synchronize 02 child processes that communicate using a buffer of size 5 using the semaphores "empty" and "full" only.
Process 01 executes producer() function and the second one executes consumer(), but the consumer functions does not execute at all even when the producer is blocked (empty=0).
after 5 iterations, I only get 5 insertions but no consuming ( I'm inserting 5's for now). Also I believe there is no need for a mutex since there are only 01 producer and 01 consumer right? here are the 02 functions and the main program:
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include <pthread.h>
#define MaxItems 5
#define BufferSize 5
sem_t empty;
sem_t full;
//pthread_mutex_t lock;
int in = 0;
int out = 0;
int buffer[BufferSize];
int N = 20;
void *producer()
{
while(1)
{
//pthread_mutex_lock(&lock);
sem_wait(&empty);
buffer[in] = 5; // fill the buffer with numbers
printf("\nInsert Item %d at %d\n", buffer[in],in);
int emptyvalue, fullValue;
sem_getvalue(&full, &fullValue); sem_getvalue(&empty, &emptyvalue);
printf("full is:%d, empty is:%d\n", fullValue, emptyvalue);
//pthread_mutex_unlock(&lock);
sem_post(&full); // increase the value of full, so the consumer should execute now?
in = (in+1)%BufferSize;
usleep(500000);
}
}
void *consumer()
{
printf("test: consumer"); //this consumer function does not execute
while (1)
{
sem_wait(&full); // full initially is = 0, so it blocks at first
//pthread_mutex_lock(&lock);
int item = buffer[out];
printf("Remove Item %d from %d\n",item, out);
//pthread_mutex_unlock(&lock);
sem_post(&empty);
printf(" %d", out); //using the values in the buffer
out = (out+1)%BufferSize;
}
}
int main()
{
//pthread_mutex_init(&lock, NULL);
sem_init(&empty,0,BufferSize);
sem_init(&full,0,0);
pid_t id1, id2;
id1 = fork();
if (id1 == 0) {
id2 = fork();
if (id2 == 0) //child 2
{
printf("im the consumer");
consumer();
}else{ //child 1
printf("i'm the producer");
producer();
}
}else{
sem_destroy(&full);
sem_destroy(&empty);
//pthread_mutex_destroy(&lock);
return 0;
}
}
thank you so much
By default, different processes live in different virtual address spaces. They cannot access each other's memory. The same is true for POSIX semaphores. This means that when you use fork to make two processes, you end up with two different sets of variables. You have a separate buffer and semaphores for each process.
To make this work, you should create a memory mapping (mmap for POSIX) where you put all the data you need to share between the processes, including the semaphores. The semaphores should be initialized with pshared to non-zero. The man page for sem_init has more details about this.
Alternatively you could use some other form of inter-process communication, like pipes.

Limit execution time of function in c

I would like to limit the execution of a function in pure C, without stopping the whole program.
I believe the closest thing on stackoverflow.com to this was on the last comment of this thread: How to limit the execution time of a function in C/POSIX?
There was some talk of using setjmp and longjm placed after the function to limit in time, but the thread died.
Is there anyone that knows if this is indeed possible?
Cheers
I can see two options, first one check the time every few lines of code and return if it's too much, but I don't think it's a good idea.
Second, you could use threads. Run two functions at the same time, one timing the other, if the time is too big then it kills the first one. Now I'm pretty sure that windows and Linux have different libraries to create threads so you could try and use a library that works across all platforms like this one maybe http://openmp.org/wp/.
I'm not too familiar with that library and threads in general but I hope it helps
Though it could be of service to post my solution. It is a combination of this post http://cboard.cprogramming.com/c-programming/148363-limit-execution-time-function.html, and the IPC TPL example found here: https://github.com/troydhanson/tpl/blob/master/doc/examples.txt.
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdbool.h>
#include <string.h>
#include "tpl.h"
//This example contains two different parts:
//1) The alarm is a execution timer for the function doWork
//2) There is a need, that if the execution exits correctly, that the chid value of i, that we are modifying be passes
typedef struct TEST_STRUCT
{
int i;
double sum;
} testStruct;
int doWork(testStruct * ts)
{
int y;
for(y=0; y<3; y++)
{
sleep(1);
printf("Working: %d\n", ts->i);
ts->i++;
ts->sum += (double)ts->i;
}
return 0;
}
int main()
{
testStruct * ts = (testStruct *)(calloc(1, sizeof(testStruct)));
ts->i = 7;
ts->sum = 4.0;
tpl_node *tn;
int fd[2];
pipe(fd);
int y;
for(y=0; y<10; y++)
{
pid_t childPID = fork();
if (childPID==0)
{
unsigned secsLeft;
alarm(10);
doWork(ts);
printf("\t->%d\n", ts->i);
printf("\t->%p\n", (void*) &ts->i);
tn = tpl_map("S(if)", ts);
tpl_pack( tn, 0 );
tpl_dump( tn, TPL_FD, fd[1]);
tpl_free( tn );
secsLeft = alarm(0);
exit(0);
}
else
{
//IMPORTANT TO PUT IT HERE: In case the buffer is too big, TPL_DUMP will wait until it can send another and hang
tn = tpl_map( "S(if)", ts );
tpl_load( tn, TPL_FD, fd[0]);
int status;
wait(&status);
if(WIFSIGNALED(status))
{
// child was interrupted
if (WTERMSIG(status) == SIGALRM)
{
printf("Interrupted\n");
// child interrupted by alarm signal
}
else
{
printf("Should not happend\n");
// child interrupted by another signal
}
}
else
{
tpl_unpack(tn,0);
tpl_free( tn );
printf("\t->%d\n", ts->i);
printf("\t->%p\n", (void*) &ts->i);
printf("Success\n");
}
}
}
return 0;
}
Basically, we fork the program, where the child performs a task and the parent waits for the child to finish. The child contains an alarm, that if true signals the parent that it existed in that manner. If it completes (as this example shows), the child sends the object function to the parent as a TPL buffer.

Pthread function starting in C

I'm actually new in processes, threads, semaphores, ipc etc(shortly operating system operations on Linux)... My problem is that I compile my code and It simply gets stuck at so funny points. Processes are executed, but they can't enter their threads' function. After that, program directly ends without doing something. I really can't figure out the problem is here or everything have problem. I don't know.
#define _GNU_SOURCE
#include <sys/types.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
void * function1(void *ptr)
{
printf("Function 1\n"); //!Test prints
printf("Index is %d",*((int *)ptr));
sleep(1);
pthread_exit(NULL);
}
void * function2(void *ptr)
{
printf("Function 2\n"); //!Test prints
printf("Index is %d",*((int *)ptr));
sleep(2);
pthread_exit(NULL);
}
int main(){
//...
int *index;
int i;
pid_t f;
int number_of_process=5;
pthread_t thread1, thread2;
//...
for(i=0; i<number_of_process; i++)
{
f=fork();
if(f==-1)
{
printf("Fork Error!!\n");
exit(1);
}
if(f==0) //To block child processes re-enter
{
*index = i; //I store index number for each process here. I'll need them in the thread functions
break;
}
}
/*******************PARENT PROCESS********************/
if(f!=0){
// wait for all children to exit
while (f = waitpid (-1, NULL, 0)){
if (errno == ECHILD)
break;
}
exit(0);
}
/*******************CHILD PROCESS*********************/
else{
pthread_create(&thread1,NULL,function1,(void *)index);
pthread_create(&thread2,NULL,function2,(void *)index);
}
}
Processes are executed, but they can't enter their threads' function.
After that, program directly ends without doing something.
That's because the main thread (i.e. child process created by fork()) doesn't wait for the threads to complete their execution. So it gives you the impression that the program exits without calling all pthread functions.
Use pthread_join() after creating threads:
...
pthread_create(&thread1,NULL,function1,(void *)index);
pthread_create(&thread2,NULL,function2,(void *)index);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
...
The output may be interleaved due to threads printing without any synchronization.

synchronizing 2 processes

I'm trying to make 2 processes start on a task at the same time (count a number, for example). I set 2 ready flags, one for each process, and perform a while loop to check if both flags are up. Then the 2 processes will start counting after the check is passed. Here's the not working code, which I don't know why:
int p1ready=0;
int p2ready=0;
int onebil = 1000000000;
int main(){
int pid;
int exit_code;
pid=fork();
if(pid==0){
//child1
int count1=0;
p1ready=1; //signal
while(!(p1ready&p2ready))'//wait until 2 processes are both ready
while(count1!=onebil){
count1++;
}
exit(0);
}
else{
pid=fork();
if(pid==0){
//child2
int count2=0;
p2ready=1; //signal
while(!(p1ready&p2ready));//wait until 2 processes are both ready
while(count2!=onebil){
count2++;
}
exit(0);
}
else{
//parent
//do stuff
}
return 0;
}
The problem with this code is, in child1 and child2, only their own ready flag is set to 1. They cannot see the flag of the other child being set. For example, child1 only sees p1ready=1, but p2ready is always 0. Why is this so? How can I fix this?
Thanks in advance!
When you do a fork() each process gets a new address space that is private. Parent and children will not share any data. That's where inter-process communication mechanisms enter.
You might use semaphores. See this links:
semaphore equivalent for processes?.
http://www.csc.villanova.edu/~mdamian/threads/posixsem.html
You can prepare semaphores on parent, have each child wait on it after each fork, and then release them in parent. Both child processes will be released and continue execution at same time. Which ones executes first depends on OS execution scheduler,of course.
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
int p1ready=0;
int p2ready=0;
int onebil = 1000000000;
int main(){
int pid;
int exit_code;
// create a semaphore for each child: value=0
sem_t *sem1 = sem_open("test_semaphore", O_CREAT|O_EXCL);
sem_t *sem2 = sem_open("test_semaphore", O_CREAT|O_EXCL);
pid=fork();
if(pid==0){
//child1
// wait on semaphore => blocks if value <= 0
sem_wait(sem1);
int count1=0;
// do work => a function might be better
while(count1!=onebil){
count1++;
}
exit(0);
}
else{
pid=fork();
if(pid==0){
//child2
// wait on semaphore => blocks if value <= 0
sem_wait(sem2);
// do work
int count2=0;
while(count2!=onebil){
count2++;
}
exit(0);
}
else{
//parent
// signal semaphore1 (increment) releasing child 1
sem_post(sem1);
// signal semaphore2 (increment) releasing child 2
sem_post(sem2);
// do work
// wait for child1/child2
int status;
wait(&status); // a child has exited
// do something with status
wait(&status); // another child has exited
// do something with status
}
return 0;
}
The way you are trying to synchronize your processes is not going to work as every process you are creating will have its own copy of p1ready and p2ready.
What you seem to be looking for is some kind of inter process communication. You might want to take a look at http://en.wikipedia.org/wiki/Inter-process_communication to see a list of possible options.
In a simple case like the one mentioned in your question most probably sending both of your child processes a signal from the parent process will be enough, so i suggest you best take a look at that.

about creating a shared memory and provide the communication between parent/child process

hi there i'm trying to implement an example of using shared memory between child and parent process. The aim is child process have to calculate a fibonacci serie with a given size as an input from user and write every number as an element of an array. After that process will printout this array. The issue is if i create this memory segment and attach it before fork() operation it works fine, after i made fork() operation child process can reach that memory segment and generate the array properly and finally parent can printout the array after child finishes its job. the code is like this;
create memory segment
attach memory segment
initialize the array elements to zero
fork()
if(pid==0)// Child Process
call the child function and send the pointer of a structure which includes the array and array size
return to parent and printout the array properly
this is first example i implemented. However, i'm trying to use an another way as you can see the full code below;
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#define MAX_SEQUENCE 10
typedef struct {
long fib_sequence[MAX_SEQUENCE];
int sequence_size;
} shared_data;
void child_func(shared_data* dataPtr);
void main(int argc,char *argv[]){
int shmID,size,status,i;
shared_data* dataPtr;
pid_t pid;
if((pid=fork())<0){
printf("Error while fork()\n");
exit(0);
}
else if(pid>0){ // Parent Process
if((shmID = shmget(IPC_PRIVATE, MAX_SEQUENCE*sizeof(long), IPC_CREAT | 0666))<0){
printf("Allocation process was unsuccesfull\n");
exit(0);
}
dataPtr = (shared_data*) shmat(shmID,NULL,0);
for(i=0; i<MAX_SEQUENCE; i++)
dataPtr->fib_sequence[i]==0;
dataPtr->sequence_size = atoi(argv[1]);
if((dataPtr->sequence_size) < 0){
printf("You entered an invalid(negative) size number\n");
exit(0);
}
else if((dataPtr->sequence_size) > MAX_SEQUENCE){
printf("Please enter a value less than MAX_VALUE\n");
exit(0);
}
wait(status); // Wait untill child finishes its job
for(i=0; i<dataPtr->sequence_size; i++)
printf("%ld ", dataPtr->fib_sequence[i]);
printf("\n");
shmdt((void *) dataPtr);
shmctl(shmID,IPC_RMID,NULL);
}
else{ // Child Process
child_func(dataPtr);
exit(0);
}
}
void child_func(shared_data* dataPtr){
int index;
printf("I am in Child Process\n");
printf("Size of array %d\n", dataPtr->sequence_size);
dataPtr->fib_sequence[0];
if((dataPtr->sequence_size) > 0){
dataPtr->fib_sequence[1]=1;
for(index=2; index < dataPtr->sequence_size; index++)
dataPtr->fib_sequence[index] = dataPtr->fib_sequence[index-1] + dataPtr->fib_sequence[index-2];
}
}
when i run the second example in when it enters in the child process it prints meaningless value of dataPtr->fib_sequence. i am curious about a few questions which are;
In the second example why it prints wrong value of dataPtr->size in child
In the first example can we admit that we do create and attach memory segment in parent process cause we are doing this stuff before fork() operation

Resources