I'm implementing a solution to a problem that uses shared memory, but somehow, my code seems to "freeze" between a print statement and an if statement.
Here's the relevant code snippet:
#include "ch_problem_headers.h"
int main(int argc, char *argv[])
{
int semid, shmid;
int i;
int waiting_C, waiting_H = 0; // shared
int c_pid,h_pid;
time_t t;
// There should be three semaphores: S for when to pass the molecule on,
// SC for the carbon waiting, and SH for the hydrogen waitin
unsigned short seminit[NUM_SEMS];
struct common *shared;
union semun semctlarg;
srand((unsigned)time(&t));
if((semid = semget(IPC_PRIVATE, NUM_SEMS, IPC_CREAT|0777)) < 0)
{
perror("semget");
exit(EXIT_FAILURE);
}
// Initialize semaphores
seminit[S_SEM] = 1;
seminit[SC_SEM] = 0;
seminit[SH_SEM] = 0;
semctlarg.array = seminit;
// Apply initialization
if((semctl(semid, NUM_SEMS, SETALL, semctlarg)) < 0)
{
perror("semctl");
exit(EXIT_FAILURE);
}
// Get shared memory id
if((shmid = shmget(IPC_PRIVATE, 1*K, IPC_CREAT|IPC_EXCL|0660)) < 0)
{
perror("shmget");
exit(EXIT_FAILURE);
}
// Retrieve pointer to shared data structure
if((shared = (struct common *)shmat(shmid, 0, 0)) < 0)
{
perror("shmat");
exit(EXIT_FAILURE);
}
shared->waiting_C = 0;
shared->waiting_H = 0;
printf("ready to fork\n");
// fork process C
c_pid = fork();
printf("c_pid is %d\n", c_pid);
if(c_pid == 0)
{
printf("I'm process C!/n");
// wait on S
semWait(semid, S_SEM);
// if waiting_H >= 4
if(shared->waiting_H >= 4)
{
// signal SH four times
for(i = 0; i < 4; i++)
{
semSignal(semid, SH_SEM);
printf("H");
}
// Decrement waiting_H by 4
shared->waiting_H -= 4;
// Signal S
semSignal(semid, S_SEM);
}
// Otherwise, increment waiting_C by 1
else
{
shared->waiting_C += 1;
// Signal S and wait for SC
semSignal(semid, S_SEM);
semWait(semid, SC_SEM);
}
}
else
{
printf("C's process id is %d\n", c_pid);
printf("ready to fork again\n");
// fork process H
h_pid = fork();
printf("Is h_pid zero? %d\n", (h_pid == 0));
if(h_pid == 0)
{
printf("I'm process H!/n");
// Wait on S
semWait(semid, S_SEM);
// If waiting_h >= 3
if(shared->waiting_H >= 3)
{
// Signal SH three times, decrement waiting_H by 3, signal SC, decrement
for(i = 0; i < 3; i++)
{
printf("H");
semSignal(semid, SH_SEM);
}
shared->waiting_H -=3;
semSignal(semid, SC_SEM);
shared->waiting_C -= 1;
semSignal(semid, S_SEM);
// waitng_C by 1, and signal S
}
// Otherwise, increment waiting_H by 1, signal S, and wait on SH
else
{
shared->waiting_H += 1;
semSignal(semid, S_SEM);
semWait(semid, SH_SEM);
}
}
else
{
printf("In the parent\n");
}
}
}
And the relevant header file:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define K 1024
#define NUM_SEMS 3
#define SEMKEY 77
#define SHMKEY 77
#define S_SEM 0
#define SH_SEM 1
#define SC_SEM 2
#define NUM_H 4
#define NUM_C 1
union semun
{
unsigned short *array;
};
struct common
{
int waiting_C;
int waiting_H;
};
void semWait(int semid, int semaphore)
{
struct sembuf psembuf;
psembuf.sem_op = -1;
psembuf.sem_flg = 0;
psembuf.sem_num = semaphore;
semop(semid, &psembuf, 1);
return;
}
void semSignal(int semid, int semaphore)
{
struct sembuf vsembuf;
vsembuf.sem_op = 1;
vsembuf.sem_flg = 0;
vsembuf.sem_num = semaphore;
semop(semid, &vsembuf, 1);
return;
}
The program output when run is as follows:
Parent output (correct) :
ready to fork
c_pid is 2977
C's process ID is 2977
ready to fork again
Is h_pid zero? 0
In the parent
Child output:
Is h_pid zero? 1
c_pid is 0
I tried running the program in valgrind, and the program simply halted after the child output. I'm confused as to how this is possible, as the program seems to simply stop between the c_pid print statement and the if(c_pid == 0) statement.
Does anyone have any idea why this might be? Thanks so much.
Related
I have N number of childs that needs to do some work in a loop while being synchronized with each other at the same time. Namely, if a child process is at its i'th iteration, all the other childs should be at i'th iteration. I need to synchronize them with semaphores but I can't find how to do it. This is the code I wrote:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/sem.h>
void sem_signal(int semid, int val) {
struct sembuf semaphore;
semaphore.sem_num = 0;
semaphore.sem_op = val;
semaphore.sem_flg = 0;
semop(semid, &semaphore, 1);
}
void sem_wait(int semid, int val) {
struct sembuf semaphore;
semaphore.sem_num = 0;
semaphore.sem_op = (-1 * val);
semaphore.sem_flg = 0;
semop(semid, &semaphore, 1);
}
int main() {
int sem_worker = semget(1, 1, 0700 | IPC_CREAT);
semctl(sem_worker, 0, SETVAL, 0);
int process_index = 0;
int N = 4, pid;
for (process_index = 0; process_index < N; process_index++) {
pid = fork();
if (pid == -1) {
printf("ERROR: cannot fork!\n");
return EXIT_FAILURE;
}
if (pid == 0)
break;
}
if (pid!=0) // parent
pause();
else {
int i = 0;
while (i < 3) {
printf("process %d: i: %d\n", process_index, i);
sem_signal(sem_worker, 1); // increase the semaphore by one
sem_wait(sem_worker, N); // wait for all the other childs
i += 1;
}
}
}
But when I run it, it can't continue after the first iteration.
process 0: i: 0
process 1: i: 0
process 3: i: 0
process 2: i: 0
process 0: i: 1
I understand why this happens. It's because one of the processes makes the semaphore 0 and continue to next iteration but all the other ones still waits. So how should I write my code to solve this problem?
P.S: I have taken sem_signal and sem_wait functions from somewhere else so I'm not sure how it works but I'm sure that they are working correctly. For example, if I write sem_wait(my_sem, num_of_children) in parent to wait all the child processes and increase my_sem by 1 in childs when they finish, it works.
As it is mentioned in the comments, you can create a barrier using semaphores and use it to synchronize your processes. You need to create your barrier in a shared memory and set a non-zero value for your semaphores' pshared parameter to share it among processes:
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include <signal.h>
#include <unistd.h>
typedef struct {
int n;
int count;
sem_t mutex;
sem_t turnstile;
sem_t turnstile2;
} barrier_t;
void init_barrier(barrier_t *barrier, int n)
{
barrier->n = n;
barrier->count = 0;
sem_init(&barrier->mutex, 1, 1); // second parameter is pshared
sem_init(&barrier->turnstile, 1, 0);
sem_init(&barrier->turnstile2, 1, 0);
}
void phase1(barrier_t *barrier)
{
sem_wait(&barrier->mutex);
if (++barrier->count == barrier->n) {
int i;
for (i = 0; i < barrier->n; i++) {
sem_post(&barrier->turnstile);
}
}
sem_post(&barrier->mutex);
sem_wait(&barrier->turnstile);
}
void phase2(barrier_t *barrier)
{
sem_wait(&barrier->mutex);
if (--barrier->count== 0) {
int i;
for (i = 0; i < barrier->n; i++) {
sem_post(&barrier->turnstile2);
}
}
sem_post(&barrier->mutex);
sem_wait(&barrier->turnstile2);
}
void wait_barrier(barrier_t *barrier)
{
phase1(barrier);
phase2(barrier);
}
int shmid, KEYSHM=123456;
int main(int argc, char const* argv[]) {
barrier_t* barrier;
shmid = shmget(KEYSHM, sizeof(barrier_t), 0700 | IPC_CREAT);
barrier = (barrier_t*) shmat(shmid, 0, 0);
int N = 4;
init_barrier(barrier, N);
shmdt(barrier);
int process_index, pid;
for (process_index = 0; process_index < N; process_index++) {
pid = fork();
if (pid == -1) {
printf("ERROR: cannot fork!\n");
return EXIT_FAILURE;
}
if (pid == 0)
break;
}
if (pid != 0) // parent
pause();
else {
int i = 0;
while (i < 3) {
barrier = (barrier_t*) shmat(shmid, 0, 0);
printf("process %d: i: %d\n", process_index, i);
i += 1;
wait_barrier(barrier);
shmdt(barrier);
}
if (process_index == 3){
kill(getppid(), SIGKILL);
}
}
}
process 0: i: 0
process 1: i: 0
process 2: i: 0
process 3: i: 0
process 2: i: 1
process 3: i: 1
process 0: i: 1
process 1: i: 1
process 3: i: 2
process 2: i: 2
process 0: i: 2
process 1: i: 2
This question already has answers here:
How to use shared memory with Linux in C
(5 answers)
Closed 4 years ago.
This is essentially what I want to do, but the outputs are junk data. What are some of the different options I have for making the child's array visible from inside the parent process?
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int foo[3]; //initialize array
pid_t pid;
pid = fork(); //create child thread
if (pid == 0) { //child:
foo[0] = 0; foo[1] = 1; foo[2] = 2; //populate array
}
else { //parent:
wait(NULL); //wait for child to finish
printf("%d %d %d", foo[0], foo[1], foo[2]); //print contents of array
}
return 0;
}
Using mmap you can create a shared memory block in your parent process. This is a basic example removing error checking for brevity.
You want to sure the proper protections and flags are set for your needs. Then hand off the address returned by mmap to your child process.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#define LIMIT_MAP 5
void child_worker(void *map)
{
int map_value = -1;
int idx = 0;
while (map_value != LIMIT_MAP) {
map_value = *((int *) map + (idx * sizeof(int)));
printf("Map value: %d\n", map_value);
idx++;
sleep(2);
}
}
int main(int argc, char *argv[])
{
printf("Starting Parent Process...\n");
long page_size = sysconf(_SC_PAGESIZE);
void *memory_map = mmap(0, page_size, PROT_WRITE | PROT_READ,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
printf("Memory map created: <%p>\n", memory_map);
pid_t pid = fork();
if (pid == 0) {
sleep(1);
printf("Starting child process\n");
child_worker(memory_map);
printf("Exiting child process...\n");
return 0;
} else {
printf("Continuing in parent process\n");
int set_values[5] = { 1, 2, 3, 4, 5 };
for (int i=0; i < 5; i++) {
printf("Setting value: %d\n", set_values[i]);
*((int *) memory_map + (sizeof(int) * i)) = set_values[i];
sleep(1);
}
waitpid(pid, NULL, 0);
printf("Child process is finished!\n");
}
return 0;
}
If fork isn't a requirement and your platform allows for it, pthread is one option. Depending on how your array is being operated on, create a thread pool passing each worker thread a copy of your array.
This is a contrived example but maybe you can pull something from it:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#define THREAD_COUNT 3
#define ITER_LIMIT 7
struct worker_params {
int idx;
int max;
bool done;
double *data;
double condition;
};
void *worker(void *arg)
{
struct worker_params *wp = (struct worker_params *) arg;
int count = 0;
while ( 1 ) {
wp->data[wp->idx] = drand48();
if (wp->max == count)
wp->done = true;
sleep(1);
count++;
}
return NULL;
}
int main(int argc, char *argv[])
{
double data[THREAD_COUNT] = { 0.0 };
pthread_t worker_1, worker_2, worker_3;
pthread_t worker_threads[] = { worker_1, worker_2, worker_3 };
struct worker_params wps[] = {
{ .idx=0, .condition=0.1, .data=data, .done=0 },
{ .idx=1, .condition=0.2, .data=data, .done=0 },
{ .idx=2, .condition=0.3, .data=data, .done=0},
};
for (int i=0; i < THREAD_COUNT; i++) {
wps[i].max = (rand() % ITER_LIMIT) + 2;
pthread_create(&worker_threads[i], NULL, worker, (void *) &wps[i]);
}
// Continue on main execution thread
int running = 1;
while ( running ) {
for (int i=0; i < THREAD_COUNT; i++) {
if (wps[i].done) {
printf("Limit hit in worker <%d>\n", i + 1);
running = 0;
break;
}
printf("Data in worker <%d> :: %g\n", i + 1, wps[i].data[i]);
}
sleep(1);
}
return 0;
}
I am working on a program that stores the variable Bank in shared memory and causes a race condition. My code compiles but it only prints the initial balance statements and not the resulting balance. Essentially, the program should be printing a balance other than 200 with the race condition and when the condition is fixed using semaphores, it should use different numbers to always print a balance of 200. What am I missing that could cause my program to get caught up after the first printf?
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <semaphore.h>
#include <string.h>
//sem_t mutex; // semaphore global variable
struct {
int balance[2];
}
Bank = {{100, 100}};
//struct Bank *bank;
// routine for thread execution
void* MakeTransactions() {
key_t shmkey;
int shmid, seqid;
int seqnum = 5858;
int i, j, tmp1, tmp2, rint;
int *shmint1, *shmint2;
double dummy;
if ((shmkey=ftok(getenv("HOME"), seqnum))==(key_t)-1) {
perror("ERROR: ftok");
}
else if ((shmid=shmget(shmkey,sizeof(int)*2,0600|IPC_CREAT))==-1) {
perror("ERROR: shmget");
}
if ((shmint1=(int *)shmat(shmid,NULL,0600))==(int*)-1) {
perror("ERROR: shmalloc");
}
shmint2 = shmint1 + 1;
// wait on semaphore
//sem_wait(&mutex);
for (i=0; i < 100; i++) {
rint = (rand()%30)-15;
if (((tmp1= *shmint1)+rint) >=0 &&
((tmp2= *shmint2)-rint)>=0) {
//sem_wait(&mutex);
//bank->balance[0] = tmp1 + rint;
*shmint1 = tmp1 + rint;
//sem_post(&mutex);
usleep(5000);
for (j=0; j < rint*100; j++) {
dummy=2.345*8.765/1.234; // spend time on purpose
}
//sem_wait(&mutex);
//bank->balance[1] = tmp2 - rint;
*shmint2 = tmp2 - rint;
//sem_post(&mutex);
}
}
Bank.balance[0]= *shmint1;
Bank.balance[1]= *shmint2;
// increment value of semaphore
//sem_post(&mutex);
return NULL;
}
vint main(int argc, char **argv) {
key_t shmkey;
int shmid, seqid, seqnum;
int *shmint1, *shmint2;
int i;
// initialize semaphore
//sem_init(&mutex, 0, 1);
// shared memory
//bank = mmap(NULL, sizeof(struct Bank), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if ((shmkey=ftok(getenv("HOME"), seqnum))==(key_t)-1) {
perror("ERROR: ftok");
}
else if ((shmid=shmget(shmkey,sizeof(int)*2,0600|IPC_CREAT))==-1) {
perror("ERROR: shmget");
}
if ((shmint1=(int *)shmat(shmid,NULL,0600))==(int*)-1) {
perror("ERROR: shmalloc");
}
shmint2 = shmint1 + 1;
memset((int*)shmint1,0,sizeof(int));
memset((int*)shmint2,0,sizeof(int));
/*//check if bank is not NULL
Bank.balance[0] = 100;
Bank.balance[1] = 100;
*/
*shmint1 = Bank.balance[0];
*shmint2 = Bank.balance[1];
pid_t pid;
srand(getpid());
printf("\nInit balances A:%d + B:%d ==> %d!\n",*shmint1,*shmint2,*shmint1 + *shmint2);
pid=fork();
if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
if (pid == 0) {
MakeTransactions();
return 0;
}
else {
MakeTransactions();
wait(NULL);
return 0;
}
printf("Let's check the balances A:%d + B:%d ==> %d ?= 200\n\n",*shmint1,*shmint2,*shmint1 + *shmint2);
//sem_destroy(&mutex);
// deattach shared memory pointer
shmdt(shmint1);
shmctl(shmid, IPC_RMID, NULL);
// memory unmap struct
//munmap(bank, sizeof(struct Bank));
return 0;
}
The wait() method you're using, as it is described here, looks like it may result in undefined behaviour when parsing NULL; it uses the integer pointer as an indicator of process completion.
I am trying to understand the concept of counting semaphore through an example. But I want to implement this using SysV in Linux.
I am familiar with theoretical part of binary semaphore and counting semaphore.
I have referred this link.
Conceptually, semaphores are used as a signaling mechanism from one process to another, so I was trying to write a simple program.
In the below program, I want thread_1 to wait till it doesn't get a signal from thread_2 and similarly thread_2 should wait till it doesn't get a signal from thread_3.
So that the output should be something like this:
Hello From thread 3
Hello from thread 2
Hello from thread 1
I know it can be achieved using pthread_join() properly but I want to achieve it using semaphores.
Code:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
int sem_id;
struct sembuf sops[3];
void thread_1(void)
{
sops[0].sem_num = 0;
sops[0].sem_op = 0;
sops[0].sem_flg = 0;
if(semop(sem_id, sops, 1) < 0)
perror("Semop In thread 3");
else
printf("Hello From thread 1\n");
}
void thread_2(void)
{
sops[0].sem_num = 0;
sops[0].sem_op = -1;
sops[0].sem_flg = 0;
if(semop(sem_id, sops, 1) < 0)
perror("Semop In thread 2");
else
printf("Hello from thread 2\n");
}
void thread_3(void)
{
sops[0].sem_num = 0;
sops[0].sem_op = -1;
sops[0].sem_flg = 0;
if(semop(sem_id, sops, 1) < 0)
perror("Semop In thread 3");
else
printf("Hello from thread 3\n");
}
int main(void)
{
void (*funct[]) = {thread_1, thread_2, thread_3};
key_t semkey;
char i;
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
}arg;
pthread_t thread_id[3];
semkey = ftok("/tmp", 'a');
if(semkey < 0)
perror("Cannot Create Semaphore Key");
else
{
sem_id = semget(semkey, 1, (IPC_CREAT|IPC_EXCL|0666));
if(sem_id < 0)
perror("Cannot create semaphore\n");
else
{
arg.val = 3;
if (semctl(sem_id, 0, SETVAL, arg) == -1) {
perror("semctl");
exit(1);
}
}
}
for(i = 0; i < 3; i++)
{
if(pthread_create(&thread_id[i], NULL, funct[i], NULL) < 0)
perror("Cannot Create thread\n");
}
for(i = 0; i < 3; i++)
pthread_join(thread_id[i], NULL);
if(semctl(sem_id, 0, IPC_RMID, NULL) == -1)
perror("semctl");
return 0;
}
Do I have to use more than one semaphore set to achieve what I am trying to do?
You need two mutexes / semaphores with count 1.
Assuming your threads are called t0,t1,t2 and your semaphores sem0 and sem1, then t0 runs freely and increments sem0, t1 waits on sem0 and increments sem1, and t2 waits on sem1.
Here's a complete draft without error checking:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
static int sem0, sem1;
#define POST1(Sem) semop(Sem, &(struct sembuf){0,1,0}, 1)
#define WAIT1(Sem) semop(Sem, &(struct sembuf){0,-1,0}, 1)
static void* t0(void *unused) { puts("hello from t0"); POST1(sem0); return 0; }
static void* t1(void *unused) { WAIT1(sem0); puts("hello from t1"); POST1(sem1); return 0; }
static void* t2(void *unused) { WAIT1(sem1); puts("hello from t2"); return 0; }
int main(void)
{
key_t sem0_k, sem1_k;
sem0_k = ftok("/tmp", '0');
sem1_k = ftok("/tmp", '1');
sem0 = semget(sem0_k, 1, (IPC_CREAT|IPC_EXCL|0666));
sem1 = semget(sem1_k, 1, (IPC_CREAT|IPC_EXCL|0666));
pthread_t tids[3];
pthread_create(tids+2, NULL, t2, NULL);
sleep(1);
pthread_create(tids+1, NULL, t1, NULL);
sleep(1);
pthread_create(tids+0, NULL, t0, NULL);
for(int i = 0; i < 3; i++)
pthread_join(tids[i], NULL);
semctl(sem0, 0, IPC_RMID, NULL);
semctl(sem1, 0, IPC_RMID, NULL);
return 0;
}
I'm running the threads in reverse order and with 1 second waits in between t0 and t1, and t1 and t2 to show the semaphores do the job of ordering the threads from t0 to t2.
#PSkocik, based on your answer, I modified my code to use a set of two semaphores. Here is the code:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
int sem_id;
struct sembuf sops;
void thread_1(void)
{
/*Wait on Set1 of Semaphore*/
sops.sem_num = 1;
sops.sem_op = -1;
sops.sem_flg = 0;
if(semop(sem_id, &sops, 1) < 0)
perror("Semop Wait In thread 3");
else
printf("Hello From thread 1\n");
}
void thread_2(void)
{
/*Wait on Set0 of Semaphore*/
sops.sem_num = 0;
sops.sem_op = -1;
sops.sem_flg = 0;
if(semop(sem_id, &sops, 1) < 0)
perror("Semop Wait In thread 2");
else
printf("Hello from thread 2\n");
/*Post on Set1 of Semaphore*/
sops.sem_num = 1;
sops.sem_op = 1;
sops.sem_flg = 0;
if(semop(sem_id, &sops, 1) < 0)
perror("Semop Post In thread 2");
}
void thread_3(void)
{
printf("Hello from thread 3\n");
/*Post operation on Set0 of semaphore*/
sops.sem_num = 0;
sops.sem_op = 1;
sops.sem_flg = 0;
if(semop(sem_id, &sops, 1) < 0)
perror("Semop In thread 3");
else
{ ; }
}
int main(void)
{
void (*funct[]) = {thread_1, thread_2, thread_3};
key_t semkey;
char i;
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
}arg;
pthread_t thread_id[3];
semkey = ftok("/tmp", 'a');
if(semkey < 0)
perror("Cannot Create Semaphore Key");
else
{
sem_id = semget(semkey, 2, (IPC_CREAT|IPC_EXCL|0666));
if(sem_id < 0)
perror("Cannot create semaphore\n");
else
{
/*arg.val = 3;
if (semctl(sem_id, 0, SETVAL, arg) == -1) {
perror("semctl");
exit(1);
}*/
}
}
for(i = 0; i < 3; i++)
{
if(pthread_create(&thread_id[i], NULL, funct[i], NULL) < 0)
perror("Cannot Create thread\n");
}
for(i = 0; i < 3; i++)
pthread_join(thread_id[i], NULL);
if(semctl(sem_id, 0, IPC_RMID, NULL) == -1)
perror("semctl");
return 0;
}
BTW, thanks a bunch for your explanation.
My problem is the stock doesnt change i think there is something wrong in the if statement pid[i] == 0. I doenst get the prints from the "father process part" of my code only from the childs.
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/types.h>
#define NUM_CHILDS 3
#define LOOPS 6
#define FILLING_UP 20
#define SHMSEGSIZE sizeof(int)
int main() {
int shmID1, shmID2, *stock, *flag, loop_i, pid[NUM_CHILDS], i;
loop_i = 1;
shmID1 = shmget(IPC_PRIVATE, SHMSEGSIZE, IPC_CREAT | 0644);
shmID2 = shmget(IPC_PRIVATE, SHMSEGSIZE, IPC_CREAT | 0644);
stock = (int *) shmat(shmID1, 0, 0);
flag = (int *) shmat(shmID2, 0, 0);
*stock = 20;
*flag = 1;
for (i = 0; i < NUM_CHILDS; i++) {
pid[i] = fork();
if(pid[i] == -1) {
printf("error by crating a child!\n\n");
return -1;
}
if (pid[i] == 0) {
printf("Child %d: %d", i, pid[i]);
while(*flag==1) {
if(*stock>0) {
*stock--;
usleep(100000);
}
}
shmdt(flag);
shmdt(stock);
return 0;
}
else {
while(loop_i <= LOOPS) {
usleep(100000);
printf("Actual stock: %d\n", *stock);
if(*stock<=0) {
*stock += FILLING_UP;
loop_i++;
printf("Stock is filled up");
}
}
*flag = 0;
}
}
for (i = 0; i < NUM_CHILDS; i++) {
waitpid(pid[i], NULL, 0);
}
printf("Programm ends", LOOPS, *stock);
shmdt(flag);
shmdt(stock);
shmctl(shmID1, IPC_RMID, 0);
shmctl(shmID2, IPC_RMID, 0);
return 0;
}
The fork() in Linux is used to create new process. Also after forking, it returns 0 in child process and returns pid of child process in parent process. So in parent process pid!=0. Hence the statement inside the if(pid==0) will not execute in parent process.
You should reset loop_i to 1. Otherwise the while loop in the parent will run LOOPS times for the first child and 0 times for the other children.
loop_i = 1;
while(loop_i <= LOOPS) {
...
}