semaphore implementation - c

I am getting error in the following program. I want to demonstrate how two processes can share a variable using semaphore. Can anyone guide me?
I am not able to debug the errors...
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<semaphore.h>
int main()
{
int pid,mutex=1;
int semid; /* semid of semaphore set */
key_t key = 1234; /* key to pass to semget() */
int nsems = 1; /* nsems to pass to semget() */
semid=semget(key,nsems,IPC_CREAT|0666);
if (semid<0)
{
perror("Semaphore creation failed ");
}
if ((pid = fork()) < 0)
{
perror("fork");
return 1;
}
else if(pid==0)
{
sem_wait(&semid);
printf("IN CHILD PROCESS :\n");
mutex++;
printf("value of shared variable =%d",mutex);
sem_post(&semid);
return 0;
}
sem_wait(&semid);
printf("IN PARENT PROCESS :\n");
mutex--;
printf("value of shared variable =%d",mutex);
sem_post(&semid);
return 0;
}

Your Fundamentals are wrong, the program won't work, so go through the basics and rewrite the program.
Some of the corrections you must make are:
1) You must make a variable of semaphore type
sem_t semvar;
2) The functions sem_wait(), sem_post() require the semaphore variable but you are passing the semaphore id, which makes no sense.
sem_wait(&semvar);
//your critical section code
sem_post(&semvar);
3) You are passing the semaphore to sem_wait() and sem_post() without initializing it. You must initialize it to 1 (in your case) before using it, or you will have a deadlock.
ret = semctl( semid, 1, SETVAL, sem);
if (ret == 1)
perror("Semaphore failed to initialize");
Study the semaphore API's from the man page and go through this example.

The fundamental issue with your code is that you mix two APIs. Unfortunately online resources are not great at pointing this out, but there are two semaphore APIs on UNIX-like systems:
POSIX IPC API, which is a standard API
System V API, which is coming from the old Unix world, but practically available almost all Unix systems
Looking at the code above you used semget() from the System V API and tried to post through sem_post() which comes from the POSIX API. It is not possible to mix them.
To decide which semaphore API you want you don't have so many great resources. The simple best is the "Unix Network Programming" by Stevens. The section that you probably interested in is in Vol #2.
These two APIs are surprisingly different. Both support the textbook style semaphores but there are a few good and bad points in the System V API worth mentioning:
it builds on semaphore sets, so once you created an object with semget() that is a set of semaphores rather then a single one
the System V API allows you to do atomic operations on these sets. so you can modify or wait for multiple semaphores in a set
the SysV API allows you to wait for a semaphore to reach a threshold rather than only being non-zero. waiting for a non-zero threshold is also supported, but my previous sentence implies that
the semaphore resources are pretty limited on every unixes. you can check these with the 'ipcs' command
there is an undo feature of the System V semaphores, so you can make sure that abnormal program termination doesn't leave your semaphores in an undesired state

Vary the consumer-rate and the producer-rate (using sleep), to better understand the operation of code. The code below is the consumer-producer simulation (over a max-limit on container).
Code for your reference:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t semP, semC;
int stock_count = 0;
const int stock_max_limit=5;
void *producer(void *arg) {
int i, sum=0;
for (i = 0; i < 10; i++) {
while(stock_max_limit == stock_count){
printf("stock overflow, production on wait..\n");
sem_wait(&semC);
printf("production operation continues..\n");
}
sleep(1); //production decided here
stock_count++;
printf("P::stock-count : %d\n",stock_count);
sem_post(&semP);
printf("P::post signal..\n");
}
}
void *consumer(void *arg) {
int i, sum=0;
for (i = 0; i < 10; i++) {
while(0 == stock_count){
printf("stock empty, consumer on wait..\n");
sem_wait(&semP);
printf("consumer operation continues..\n");
}
sleep(2); //consumer rate decided here
stock_count--;
printf("C::stock-count : %d\n", stock_count);
sem_post(&semC);
printf("C::post signal..\n");
}
}
int main(void) {
pthread_t tid0,tid1;
sem_init(&semP, 0, 0);
sem_init(&semC, 0, 0);
pthread_create(&tid0, NULL, consumer, NULL);
pthread_create(&tid1, NULL, producer, NULL);
pthread_join(tid0, NULL);
pthread_join(tid1, NULL);
sem_destroy(&semC);
sem_destroy(&semP);
return 0;
}

Please check this out below sample code for semaphore implementation(Lock and unlock).
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include<string.h>
#include<malloc.h>
#include <sys/sem.h>
int main()
{
int key,share_id,num;
char *data;
int semid;
struct sembuf sb={0,-1,0};
key=ftok(".",'a');
if(key == -1 ) {
printf("\n\n Initialization Falied of shared memory \n\n");
return 1;
}
share_id=shmget(key,1024,IPC_CREAT|0744);
if(share_id == -1 ) {
printf("\n\n Error captured while share memory allocation\n\n");
return 1;
}
data=(char *)shmat(share_id,(void *)0,0);
strcpy(data,"Testing string\n");
if(!fork()) { //Child Porcess
sb.sem_op=-1; //Lock
semop(share_id,(struct sembuf *)&sb,1);
strncat(data,"feeding form child\n",20);
sb.sem_op=1;//Unlock
semop(share_id,(struct sembuf *)&sb,1);
_Exit(0);
} else { //Parent Process
sb.sem_op=-1; //Lock
semop(share_id,(struct sembuf *)&sb,1);
strncat(data,"feeding form parent\n",20);
sb.sem_op=1;//Unlock
semop(share_id,(struct sembuf *)&sb,1);
}
return 0;
}

Related

sem_init and pthread_mutex_init

I was writing 2 similar codes for printing odd and even numbers from given number set using mutex lock and semaphore. Both of the codes works fine.
But, while using mutex lock, even if I wont declare the pthread_mutex_init function, still the program executes with no issues. But that's not the case with semaphore. For this case, I have to declare sem_init in main() else the program execution gets stuck in sem_wait() (found after debugging).
So, how in the case of mutex lock, even without declaring init(), the program executes?
For reference, I am attaching the semaphore code.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
sem_t mutex;
pthread_t tid[2];
unsigned int shared_data[] = {23,45,67,44,56,78,91,102};
unsigned int rc;
int len=(sizeof(shared_data)/sizeof(shared_data[0]));
int i=0;
void *even(void *arg) {
rc = sem_wait(&mutex);
int temp = rc;
if(rc)
printf("Semaphore failed\n");
do{
if(shared_data[i] %2 == 0) {
printf("Even: %d\n",shared_data[i]);
i++;
}
else
rc = sem_post(&mutex);
}while(i<len);
}
void *odd(void *arg) {
rc = sem_wait(&mutex);
if(rc)
printf("Semaphore failed\n");
do {
if(shared_data[i] %2 != 0) {
printf("Odd: %d\n",shared_data[i]);
i++;
}
else
rc = sem_post(&mutex);
}while(i<len);
}
int main() {
sem_init(&mutex, 0,1);
pthread_create(&tid[0], 0, &even, 0);
pthread_create(&tid[1], 0, &odd, 0);
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
sem_destroy(&mutex);
return 0;
}
EDIT: Attaching the mutex lock code as well.
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
pthread_t tid[2];
unsigned int shared_data []= {23,45,67,44,56,78,91,102};
pthread_mutex_t mutex;
unsigned int rc;
int len=(sizeof(shared_data)/sizeof(shared_data[0]));
int i=0;
void* PrintEvenNos(void *ptr)
{
rc = pthread_mutex_lock(&mutex);
if(rc)
printf("Mutex lock has failed\n");
do
{
if(shared_data[i]%2 == 0)
{
printf("Even:%d\n",shared_data[i]);
i++;
} else {
rc=pthread_mutex_unlock(&mutex);
}
} while(i<len);
}
void* PrintOddNos(void* ptr1)
{
rc = pthread_mutex_lock(&mutex);
if(rc)
printf("Mutex lock has failed\n");
do
{
if(shared_data[i]%2 != 0)
{
printf("Odd:%d\n",shared_data[i]);
i++;
} else {
rc=pthread_mutex_unlock(&mutex);
}
} while(i<len);
}
void main(void)
{
pthread_create(&tid[0],0,PrintEvenNos,0);
pthread_create(&tid[1],0,PrintOddNos,0);
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
}
So, how in the case of mutex lock, even without declaring init(), the program executes?
This is undefined behavior, so there is no proper result. Per POSIX pthread_mutex_lock():
If mutex does not refer to an initialized mutex object, the behavior of pthread_mutex_lock(), pthread_mutex_trylock(), and pthread_mutex_unlock() is undefined.
"Appears to work" is one possible result of undefined behavior.
You have sem_init call for sem_t mutex;.
But pthread_mutex_init call is missing for pthread_mutex_t mutex;.
Both of the codes works fine.
No they don't; but first:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Is how you should have initialized your mutex. On your system, this value might be zero, which would be equivalent to what you have. Either way, the problem is your program is broken.
One of your threads (even, odd) acquires a lock. In the case of even, when i is 0,1,2,5 or 6; you unlock it, which would permit odd() to proceed. In the case of odd, when i is 3,4,5 or 7, you unlock it, which would permit even() to proceed. So in your logic, the lock does nothing at all.
Also, semaphores are counters; so when you release it 5 times, you are permitting the next 5 sem_waits to proceed. Simple mutexes are gates, so only the first unlock has any effect, the subsequent 4 are errors. You don't check the error status of the unlock, which is typically the one that uncovers logic errors.
fwiw, on macos, the pthread_mutex_lock()'s both report an error.

Pthread signalling in C Linux

I am working with multi-threading in Linux using Pthread.
Thread1 waits for an IRQ from Driver by polling a character device file (my driver has ISR to catch IRQ from HW).
IRQ -----> Thread1 |-----> Thread2
|-----> Thread3
|-----> Thread4
Whenever Thread1 gets an IRQ, I want send a signal to Thread2, Thread3 and Thread4 to wake them up and then work.
Now, I am trying to use "pthread conditional variable" and "pthread mutex". But it seems that is not good approach.
What is efficient way for synchronization in this case? Please help.
Thank you very much.
As I understand it, your problem is that your child threads (Threads 2 through 4) don't always wake up exactly once for every IRQ that Thread1 receives -- in particular, it might be that an IRQ is received while the child threads are already awake and working on an earlier IRQ, and that causes them not to be awoken for the new IRQ.
If that's correct, then I think a simple solution is to use a counting semaphore for each child-thread, rather than a condition variable. A semaphore is a simple data structure that maintains an integer counter, and supplies two operations, wait/P and signal/V. wait/P decrements the counter, and if the counter's new value is negative, it blocks until the counter has become non-negative again. signal/V increments the counter, and in the case where the counter was negative before the increment, awakens a waiting thread (if one was blocked inside wait/P).
The effect of this is that in the case where your main thread gets multiple IRQs in quick succession, the semaphore will "remember" the multiple signal/V calls (as a positive integer value of the counter), and allow the worker-thread to call wait/P that-many times in the future without blocking. That way no signals are ever "forgotten".
Linux supplies a semaphore API (via sem_init(), etc), but it's designed for inter-process synchronization and is therefore a little bit heavy-weight for synchronizing threads within a single process. Fortunately, it's easy to implement your own semaphore using a pthreads mutex and condition-variable, as shown below.
Note that in this toy example, the main() thread is playing the part of Thread1, and it will pretend to have received an IRQ every time you press return in the terminal window. The child threads are playing the part of Threads2-4, and they will pretend to do one second's worth of "work" every time Thread1 signals them. In particular note that if you press return multiple times in quick succession, the child threads will always do that many "work units", even though they can only perform one work-unit per second.
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
struct example_semaphore
{
pthread_cond_t cond;
pthread_mutex_t mutex;
int count; // acccess to this is serialized by locking (mutex)
};
// Initializes the example_semaphore (to be called at startup)
void Init_example_semaphore(struct example_semaphore * s)
{
s->count = 0;
pthread_mutex_init(&s->mutex, NULL);
pthread_cond_init(&s->cond, NULL);
}
// V: Increments the example_semaphore's count by 1. If the pre-increment
// value was negative, wakes a process that was waiting on the
// example_semaphore
void Signal_example_semaphore(struct example_semaphore * s)
{
pthread_mutex_lock(&s->mutex);
if (s->count++ < 0) pthread_cond_signal(&s->cond);
pthread_mutex_unlock(&s->mutex);
}
// P: Decrements the example_semaphore's count by 1. If the new value of the
// example_semaphore is negative, blocks the caller until another thread calls
// Signal_example_semaphore()
void Wait_example_semaphore(struct example_semaphore * s)
{
pthread_mutex_lock(&s->mutex);
while(--s->count < 0)
{
pthread_cond_wait(&s->cond, &s->mutex);
if (s->count >= 0) break;
}
pthread_mutex_unlock(&s->mutex);
}
// This is the function that the worker-threads run
void * WorkerThreadFunc(void * arg)
{
int workUnit = 0;
struct example_semaphore * my_semaphore = (struct example_semaphore *) arg;
while(1)
{
Wait_example_semaphore(my_semaphore); // wait here until it's time to work
printf("Thread %p: just woke up and is working on work-unit #%i...\n", my_semaphore, workUnit++);
sleep(1); // actual work would happen here in a real program
}
}
static const int NUM_THREADS = 3;
int main(int argc, char ** argv)
{
struct example_semaphore semaphores[NUM_THREADS];
pthread_t worker_threads[NUM_THREADS];
// Setup semaphores and spawn worker threads
int i = 0;
for (i=0; i<NUM_THREADS; i++)
{
Init_example_semaphore(&semaphores[i]);
pthread_create(&worker_threads[i], NULL, WorkerThreadFunc, &semaphores[i]);
}
// Now we'll pretend to be receiving IRQs. We'll pretent to
// get one IRQ each time you press return.
while(1)
{
char buf[128];
fgets(buf, sizeof(buf), stdin);
printf("Main thread got IRQ, signalling child threads now!\n");
for (i=0; i<NUM_THREADS; i++) Signal_example_semaphore(&semaphores[i]);
}
}
I like jeremy's answer, but it does have some lacking in that the interrupt dispatcher needs to know how many semaphores to increment on each interrupt.
Also each increment is potentially a kernel call, so you have a lot of kernel calls for each interrupt.
An alternate is to understand how pthread_cond_broadcast() works. I have put an example below:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#ifndef NTHREAD
#define NTHREAD 5
#endif
pthread_mutex_t Lock;
pthread_cond_t CV;
int GlobalCount;
int Done;
#define X(y) do { if (y == -1) abort(); } while (0)
void *handler(void *x) {
unsigned icount;
X(pthread_mutex_lock(&Lock));
icount = 0;
while (!Done) {
if (icount < GlobalCount) {
X(pthread_mutex_unlock(&Lock));
icount++;
X(pthread_mutex_lock(&Lock));
} else {
X(pthread_cond_wait(&CV, &Lock));
}
}
X(pthread_mutex_unlock(&Lock));
return NULL;
}
int
main()
{
X(pthread_mutex_init(&Lock, NULL));
X(pthread_cond_init(&CV, NULL));
pthread_t id[NTHREAD];
int i;
for (i = 0; i < NTHREAD; i++) {
X(pthread_create(id+i, NULL, handler, NULL));
}
int c;
while ((c = getchar()) != EOF) {
X(pthread_mutex_lock(&Lock));
GlobalCount++;
X(pthread_mutex_unlock(&Lock));
X(pthread_cond_broadcast(&CV));
}
X(pthread_mutex_lock(&Lock));
Done = 1;
X(pthread_cond_broadcast(&CV));
X(pthread_mutex_unlock(&Lock));
for (i = 0; i < NTHREAD; i++) {
X(pthread_join(id[i], NULL));
}
return 0;
}

Thread synchronisation using semaphore for c

I am writing a c program to create three threads(1,2,3) such that at any given point of time only one thread must execute and print the output on console in the order 123123123123.........
I am making use of semaphore for synchronization.
I am having an issue with the code i have written. the code doesn't print it in the order 123123... the order is random and stops after a while.
#include<stdio.h>
#include<semaphore.h>
#include<pthread.h>
#include<unistd.h>
#include<assert.h>
#include<stdlib.h>
sem_t sem_1;
void *func1(void *arg){
int err1=0;
while(1){
err1=sem_wait(&sem_1);
assert(err1==0);
printf("thread 1\n");
}
//return NULL;
}
void *func2(void *arg){
int err2=0;
while(1){
err2=sem_wait(&sem_1);
assert(err2==0);
printf("thread 2\n");
}
// return NULL;
}
void *func3(void *arg){
int err3=0;
while(1){
err3=sem_wait(&sem_1);
assert(err3==0);
printf("thread 3\n");
}
// return NULL;
}
int main(){
pthread_t *t1,*t2,*t3;
int i=0,rc=0,c1=0,c2=0,c3=0;
t1=(pthread_t *)malloc(sizeof(*t1));
t2=(pthread_t *)malloc(sizeof(*t2));
t3=(pthread_t *)malloc(sizeof(*t3));
i=sem_init(&sem_1,0,1);
assert(i==0);
c1=pthread_create(t1,NULL,func1,NULL);
assert(c1==0);
c2=pthread_create(t2,NULL,func2,NULL);
assert(c2==0);
c3=pthread_create(t3,NULL,func3,NULL);
assert(c3==0);
while(1){
rc=sem_post(&sem_1);
assert(rc==0);
sleep(1);
}
return 0;
}
Why would you even expect them in in an order?
Your threads do things inbetween the different waits, and according to the system scheduler, these can take different amount of time.
printf is a buffered operation that gives you exclusive access to a shared resource. So in addition to your semaphore there is a hidden lock somewhere, that also regulates the progress of your threads. Don't expect the prints to appear in order, even if the calls themselves are.
Then, for the end, using assert here is really a very bad idea. All sem_t operations can (and will) fail spuriously, so it is really bad to abort, just because such a failure.
In fact, sem_t is really a low level tool, and you should never use it without checking return values and without having a fall back strategy if such a call fails.
Of course. I can't see any order related synchronization mechanism.
One of the options to achieve the strict order is to have one semaphore per thread:
sem_t sem[3];
// ...
while(1) {
for(n = 0; n < 3; n++) {
rc=sem_post(&sem[n]);
assert(rc==0);
}
sleep(1);
}
Below Code will help to solve the problem, one semaphore for each thread used to achieve synchronization. The initial value of the semaphore does the job. used usleep to launch thread in sequence manner for needed output. The same can be done by using Mutex lock and cond variables
//declaring semaphore
sem_t sema1;
sem_t sema2;
sem_t sema3;
void* t1(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema1);
printf("Thread 1 \n");
sem_post(&sema2);
}
printf("T1 return\n");
return NULL;
}
void* t2(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema2);
printf("Thread 2 \n");
sem_post(&sema3);
}
printf("T2 return\n");
return NULL;
}
void* t3(void *arg)
{
for(int j=0;j<10;j++)
{
sem_wait(&sema3);
printf("Thread 3 \n");
sem_post(&sema1);
}
printf("T3 return \n");
return NULL;
}
int main()
{
pthread_t tid1, tid2,tid3;
sem_init(&sema1,0,1);
sem_init(&sema2,0,0);
sem_init(&sema3,0,0);
pthread_create(&tid1, NULL, t1, NULL);
usleep(100);
pthread_create(&tid2, NULL, t2, NULL);
usleep(100);
pthread_create(&tid3, NULL, t3, NULL);
pthread_join(tid3, NULL);
pthread_join(tid2, NULL);
pthread_join(tid1, NULL);
sem_destroy(&sema1);
sem_destroy(&sema2);
sem_destroy(&sema3);
return 0;
}

Wait for all processes reach some point in program, then resume

I have an application which creates many processes via fork(). At some point I want to pause them all and wait until all of them finish earlier tasks. Then start them all at once.
for (int i = 0; i < N; i++)
{
if(fork() == 0)
{
//some operations here
<----- wait here for all N forked processes
//some operations I want all processes start at similiar time
I don't want any of children to quit.
This seems tailor-made for a semaphore. Specifically, this is easy to implement with "System V semaphores". See semget(2) and semop(2).
The idea is that you obtain a semaphore in the parent, initialize its value to N, then have each child as it's "ready" decrement the value by 1. All children wait for the result to become 0. Voila.
Here's a sample program
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define N 5
int main(int ac, char **av)
{
int i, n, sem_id;
sem_id = semget(IPC_PRIVATE, 1, 0777);
struct sembuf buf;
buf.sem_num = 0;
buf.sem_flg = 0;
// Initialize semaphore value to N
buf.sem_op = N;
n = semop(sem_id, &buf, 1);
// All children will do the same thing:
// decrement semaphore value by 1
// wait for semaphore value == 0
for (i = 0; i < N; ++i) {
if (fork() == 0) {
printf("Child %d (%d) started\n", i, getpid());
sleep(i + 1); // Sleep awhile.
buf.sem_op = -1;
n = semop(sem_id, &buf, 1);
buf.sem_op = 0;
n = semop(sem_id, &buf, 1);
printf("Child %d (%d) done\n", i, getpid());
return 0;
}
}
return 0;
}
There are many ways to communicate with processes, it is called IPC (Inter Process Communication). It depends on what kind of information you need to send, how large etc. Process signals is also a way to control processes.
Here are a few resources to get you started:
Personally I like Beej Guides, which are awsome, clear, concise and FREE!
http://beej.us/guide/bgipc/
There is also Advanced Linux Programming by CodeSourcery LLC.
http://www.advancedlinuxprogramming.com/
And of course, once you have some notions of the basics, you can look up more specifically http://stackoverflow.com, i.e. right here :-)
What you can use is a synchronization construct like semaphore.
At the point of code where you want to stop all childrens make them wait in queue (call wait on a semaphore with 0 as initial value )of semaphore and thus they all will block.
In parent then you can signal semaphore and thus start them all.
I would highly recommend Message Passing Interface (MPI) for this, since it has MPI_Barrier that you can used to achieve exactly what you want with almost no logic you have to code yourself. There are alternatives such as OpenMP as well.
I've managed to resolve this via group signals:
for (int i = 0; i < N; i++)
{
if(fork() == 0)
{
/* save first process pid in shared memory */
if(localID == 0)
*sh_temp = getpid();
/* wait in all processes for shared memory with group id to be set */
while(*sh_temp == 0)
usleep(10000);
/* set group id to first process PID */
setpgid(getpid(), *sh_temp);
//some operations here
fprintf(stderr, "Process %d paused... W8ing for signal to resume\n", getpid());
raise(SIGSTOP);
//some operations I want all processes start at similiar time
}
}
if(parentPID == getpid())
{
fprintf(stderr, "Wake-up signal sent to group %ld.\n", *sh_temp);
killpg(*sh_temp, SIGCONT);
}
But - if anyone has better solution please post it.

Dining Philosophers in C using fork()

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.

Resources