This is my first post and I'm excited.
My problem is that I am creating a Rock, Paper, Scissors program in C where the parent process creates 2 threads. The 2 threads then throw a random rock, paper, or scissors and return the value to the parent where it gets counted and spits back the results of 3 rounds, then makes a final tally.
My problem is that I cannot get the threads to initiate correctly, I have them waiting in my thread_function1 but then they only complete one round and even then I don't get two threads back in the results. If someone could please shed some light I would really appreciate it! Thanks
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
#define NTHREADS 2
struct timeval tv;
void *thread_function1();
void *thread_function2();
char *guess_string(int g);
int wins[3];
int cmd_ready = 0;
int x1=0, x2=1, count=0;
int guess, object, turns, i, j, k,l, winner, cmd, go, y;
pthread_mutex_t cv_m;
pthread_mutex_t count_mutex;
pthread_cond_t cv;
int myindex;
int flag;
int throws[3];
int main(int argc, char *argv[])
{
wins[0] = 0; wins[1] = 0;
if ((argc != 2) || ((turns = atoi(argv[1])) <= 0))
{
fprintf(stderr,"Usage: %s turns\n", argv[0]);
return 0;
}
pthread_t thread_id1, thread_id2;
if (pthread_create(&thread_id1, NULL, thread_function1,&x1) != 0)
perror("pthread_create"),
exit(1);
if (pthread_create(&thread_id2, NULL, thread_function1,&x2) != 0)
perror("pthread_create"),
exit(1);
printf("Beginning %d Rounds...\nFight!\n", turns);
printf("Child 1 TID: %d\n", (unsigned int) thread_id1);
printf("Child 2 TID: %d\n", (unsigned int) thread_id2 );
for(k=0; k<turns; k++)
{
pthread_mutex_lock (&cv_m);
cmd = go;
cmd_ready = 2;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&cv_m);
printf("------------------------\n");
printf("Round: %d\n", k+1);
printf("Child %d throws %s!\n",myindex+1, guess_string(myindex));
pthread_mutex_lock (&count_mutex);
winner = find_winner(throws[0], throws[1]);
while(count == 2){
if(winner >= 0)
{
printf("Child %d Wins!\n", winner+1);
wins[winner]++;
printf("6\n");
}else
{
printf("Game is a Tie!\n");
}
go--;
count = 0;
pthread_mutex_unlock(&count_mutex);
}
}
pthread_join(thread_id1,NULL);
pthread_join(thread_id2,NULL);
printf("------------------------\n");
printf("------------------------\n");
printf("Result:\n");
printf("Child 1: %d\n", wins[0]);
printf("Child 2: %d\n", wins[1]);
printf("Ties: %d\n", turns - (wins[0] + wins[1]));
printf("Child %d Wins!\n", (wins[0] > wins[1]) ? 1 : 2);
pthread_mutex_destroy(&cv_m);
pthread_cond_destroy(&cv);
pthread_exit(NULL);
return 0;
}
void *thread_function1(void *p)
{
struct timeval tv;
myindex = *(int *)p;
gettimeofday(&tv, NULL);
srand(tv.tv_sec + tv.tv_usec + getpid());
printf("1\n");
pthread_mutex_lock (&cv_m);
while(cmd_ready == 0)
{
printf("2\n");
pthread_cond_wait(&cv, &cv_m);
}
printf("3\n");
throws[myindex] = rand() % 3;
cmd_ready--;
printf("Ready: %d\n",cmd_ready);
pthread_mutex_unlock (&cv_m);
printf("4\n");
pthread_mutex_lock (&count_mutex);
count++;
printf("Count %d\n", count);
pthread_mutex_unlock(&count_mutex);
while(count == 2){
printf("5\n");
return NULL;
}
}
char *guess_string(int g){
switch(g){
case 0:
return "Rock";
break;
case 1:
return "Paper";
break;
case 2:
return "Scissors";
break;
}
}
int find_winner(int g1, int g2){
if(g1 == g2)
return -1;
else if ((g1 == 2) && (g2 == 0))
return 1;
else if ((g1 == 0) && (g2 == 2))
return 0;
else
return (g1 > g2) ? 0 : 1;
}
You don't appear to be initializing your mutex or condition with pthread_mutex_init or pthread_cond_init.
The variable myindex is being modified by both threads without protection, the second thread to update this variable will be the one that appears to report back.
You are also counting on your threads to begin pending on the condition before main grabs the lock and issues the broadcast, you could have a case where main gets there first and your threads won't be ready.
That should be a start.
Related
I have a parent thread which creates child threads A,B,C,D,E,F. Each of these child threads runs a different disk scheduling algorithm and prints the result simultaneously. The task is to block these child threads while the parent thread waits for the user to input a file name, from which the disk scheduling data is parsed and read in order to be used in the disk scheduling algorithms for the child threads.
Currently my program first takes the user input before the creation of the child threads and therefor there is no need to block however my task is to block them.
#define N 71
typedef struct
{
int totalCylinders;
int cylindersInReqQueue;
int currentPos;
int prevDiskRequest;
int *requestQueueArr;
char id;
char *filename;
} disk_data;
sem_t semaphore;
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex;
void *runner(void *args);
void runscheduler(char name, disk_data data);
void *runner(void *args)
{
disk_data data = *(disk_data*)args;
char threadName = data.id;
pthread_mutex_lock(&mutex);
while(strlen(data.filename) == 0)
{
printf("IT REACHED THIS> GOING OUT");
pthread_cond_wait(&cond1, &mutex);
}
printf("Hello from thread %u I am %c\n", (int)pthread_self(),threadName);
runscheduler(threadName,data);
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void runscheduler(char name, disk_data data)
{
switch(name)
{
case 'A' :
firstComeFirstServe(data.cylindersInReqQueue, data.currentPos, data.requestQueueArr);
break;
case 'B' :
shortestSeekTimeFirst(data.totalCylinders, data.cylindersInReqQueue, data.currentPos, data.requestQueueArr);
break;
case 'C' :
scan(data.totalCylinders, data.currentPos, data.prevDiskRequest, data.cylindersInReqQueue, data.requestQueueArr);
break;
case 'D' :
cScan(data.totalCylinders, data.currentPos, data.prevDiskRequest, data.cylindersInReqQueue, data.requestQueueArr);
break;
case 'E' :
look(data.totalCylinders,data.currentPos,data.prevDiskRequest,data.cylindersInReqQueue,data.requestQueueArr);
break;
case 'F' :
cLook(data.totalCylinders,data.currentPos,data.prevDiskRequest,data.cylindersInReqQueue,data.requestQueueArr);
break;
default :
printf("Invalid grade\n" );
}
}
int main(int argc, char*argv[])
{
disk_data dd;
pthread_t tid[N];
int* res;
char *input;
int i,ret;
dd.cylindersInReqQueue =0;
dd.requestQueueArr = (int *) malloc(dd.cylindersInReqQueue * sizeof(int));
pthread_mutex_init(&mutex, NULL);
printf("***Disk Scheduler Simulation***");
input = readAndParse(&dd.totalCylinders, &dd.cylindersInReqQueue, &dd.currentPos, &dd.prevDiskRequest, &dd.requestQueueArr);
dd.filename = input;
for(i = 65; i < N; i++)
{
dd.id = (char)i;
ret = pthread_create(&tid[i], NULL, &runner, &dd);
if(ret != 0)
{
perror("Error: pthread_create() failed\n");
}
sleep(1);
printf ("Thread %c is created\n", i);
}
for(i = 65; i < N; i++)
{
if (pthread_join(tid[i], (void **) &res) != 0)
{
perror("Failed to join thread");
}
printf ("Thread %c has terminated\n", i);
}
pthread_mutex_destroy(&mutex);
printf ("All threads are now finished\n");
pthread_exit(NULL);
return 0;
}
I'm doing an assignment in C where we have a narrow road that can only support up to three cars at a time. The road is one-way so cars are allowed to go either East or West. Starvation should also be avoided. My implementation so far seems to work generally but I'm having a hard time understanding why the numOfCarsOnRoad variable has inconsistent values (i.e. printing 'Number of cars on the road = 1' twice in the output instead of '.. = 3', '.. = 2', '.. = 1') despite each thread incrementing/decreasing it each time.
Furthermore, I've noticed that if for example three threads "start" one after another (thus calling sleep(1)), they may finish in a different order. I understand that each thread runs in a separate lightweight process but shouldn't the sleep(1) last shorter for the thread that went first? Is there a way to avoid this?
The number of cars (represented by threads) is passed via the cmd args (i.e. '-c 5').
header:
void * crossBridge(void *i);
void parseCarArg(int argc, char *argv[]);
C:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include "ask2.h"
sem_t sem;
int numOfCarsOnRoad = 0;
int carsGoingW = 0;
int carsGoingE = 0;
long numOfCars = 0; // used for thread initializations
char currActiveDir = '_'; // either W or E ( _ initially)
void *crossBridge(void *i)
{
int id = *((int *)i);
char direction[5];
if (rand() % 2 == 0) {
strcpy(direction, "West");
carsGoingW++;
}
else {
strcpy(direction, "East");
carsGoingE++;
}
if (currActiveDir == '_')
currActiveDir = direction[0];
printf("Car #%d waiting to pass to the %s...\n", id, direction);
while (currActiveDir != direction[0] || numOfCarsOnRoad == 3)
{
sleep(2);
}
sem_wait(&sem); // enter critical region
numOfCarsOnRoad++;
printf("Car #%d going to the %s. Number of cars on the road = %d\n", id, direction, numOfCarsOnRoad);
sleep(1);
numOfCarsOnRoad--;
sem_post(&sem);
printf("Car #%d crossed to the %s! Number of cars on the road = %d\n", id, direction, numOfCarsOnRoad);
if(direction[0] == 'W') carsGoingW--;
else carsGoingE--;
// helps to avoid starvation
if (numOfCarsOnRoad == 0)
{
if (currActiveDir == 'W' && carsGoingE > 0)
currActiveDir = 'E';
else if (currActiveDir == 'E' && carsGoingW > 0)
currActiveDir = 'W';
}
pthread_exit(NULL);
}
void parseCarArg(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++)
{
if (strcmp(argv[i], "-c") == 0)
{
if (++i < argc && strlen(argv[i]) > 0)
numOfCars = strtol(argv[i], NULL, 10); // convert to long
if (numOfCars == 0)
{
perror("You must enter a number of cars > 0!\n");
exit(EXIT_FAILURE);
}
break;
}
}
}
int main(int argc, char *argv[])
{
if (argc == 0)
exit(EXIT_FAILURE);
parseCarArg(argc, argv);
srand(time(NULL)); // seed the generator using epoch time in millis
if (sem_init(&sem, 0, 3) == -1)
{
perror("Failed to initialize semaphore!\n");
exit(EXIT_FAILURE);
}
pthread_t cars[numOfCars];
int i;
for (i = 0; i < numOfCars; i++)
{
if (pthread_create(&cars[i], NULL, crossBridge, &i) != 0)
{
perror("Failed to create threads for the cars!\n");
exit(EXIT_FAILURE);
}
}
// wait for all threads to finish
for (i = 0; i < numOfCars; i++)
pthread_join(cars[i], NULL);
sem_destroy(&sem);
return 0;
}
I've got my code down for a dining philosopher problem, using shared memory. The issue I'm encountering is that 3 of 5 philosophers are eating which shouldn't be happening. Where am I going wrong in my code?
Updated: still not working right. Philosophers seem to not be going through one of the states
#include <stdio.h> // needed for printf, sprintf, ...
#include <stdlib.h> // needed for exit()
#include <unistd.h> // needed for sleep, fork, waitpid, _exit, ftruncate
#include <sys/wait.h> // needed for waitpid
#include <fcntl.h> // For O_* constants
#include <sys/mman.h> // needed for mmap, munmap and associated constants
#include <semaphore.h>
void philosopher(int i);
int parent(void);
void take_forks(int i);
void put_forks(int i);
void test (int i);
void think(int i);
void eat(int i);
#define N 5 /* number of philosophers */
#define THINKING 0 /* philosopher is thinking */
#define HUNGRY 1 /* philosopher is trying to get for ks */
#define EATING 2 /* philosopher is eating */
#define FINISH 3
#define LEFT (arga+4)%N
#define RIGHT (arga+1)%N
struct shared_memory {
int k;
int state[N];
sem_t s[N];
sem_t mutex;
};
struct shared_memory *shared;
int fd_shm, fd_log;
int main(void) {
if ((fd_shm = shm_open ("/test", O_RDWR | O_CREAT, 0660)) == -1)
printf("error");
if (ftruncate (fd_shm, sizeof (struct shared_memory)) == -1)
printf("error");
if ((shared = mmap (NULL, sizeof (struct shared_memory), PROT_READ | PROT_WRITE, MAP_SHARED,fd_shm, 0)) == MAP_FAILED)
printf("error");
// Initialize the shared memory
shared -> k = 0;
for (int i=0; i<N;i++){
shared -> state[i] = 0;
sem_init(&shared->s[i],0,1);
}
sem_init(&shared->mutex,1,1);
pid_t pids[N];
// At the beginning every philosopher is thinking
for (int l = 0; l < N; l++){
shared ->state[l]=THINKING;
}
printf("Start");
for(int j=0; j< N; j++){
if((pids[j] = fork()) < 0){
printf("failed");
perror("fork");
}else if (pids[j] == 0 ){
int pid = getpid();
printf("pids[%d] = %d\n",j,pid);
philosopher(j);
exit(0);
}
}
parent();
for (int m=0; m<N;m++){
waitpid(pids[m],NULL,0);
}
printf("This is final k %d\n",shared->k);
if (munmap(shared, sizeof(struct shared_memory)) == -1) {
printf("Function munmap() failed\n");
exit(-1);
}
if ((shm_unlink("/test")) == -1){
printf("Function shm_unlink() failed\n");
exit(-1);
}
return EXIT_SUCCESS;
}
void philosopher(int arga) {
//int count =0;
//while(count<5){
while(1){
//sleep(1);
//think(i);
take_forks(arga);
sleep(2);
//eat(i);
//sleep(1);
put_forks(arga);
//count++;
}
shared->state[arga] = FINISH;
}
void take_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga take_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutex */
shared->state[arga] = HUNGRY; /* record fact that philosopher i is hungry */
//while (shared->state[i] == HUNGRY){
test(arga); /* try to acquire 2 forks */
sem_post(&shared->mutex); /* exit critical region, up mutex */
//sem_wait(&shared->s[arga]); /* block if forks were not acquired, down philosopher*/
//}
//sleep(1);
}
void put_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga put_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutes */
//test(LEFT); /* see if left neighbor can now eat */
//test(RIGHT); /* see if right neighbor can now eat */
shared->state[arga] = THINKING; /* philosopher has finished eating */
sem_post(&shared->mutex); /* exit critical region, up mutex */
}
void test(int arga) /* i: philosopher number, from 0 to N−1 */
{
sem_wait(&shared->s[LEFT]);
sem_wait(&shared->s[RIGHT]);
shared->state[arga]= EATING;
sleep(1);
sem_post(&shared->s[RIGHT]);
sem_post(&shared->s[LEFT]);
//if (shared->state[arga] == HUNGRY && shared->state[LEFT] != EATING && shared->state[RIGHT] != EATING)
//{
//printf("Philosopher: %d (i+N-1)%N - %d", i, ((i+N-1)%N));
//shared->state[arga] = EATING;
//sleep(2);
//sem_post(&shared->s[arga]); //Up philosopher
//}
}
void think(int arga){
//printf("I am philosopher %d i am thinking\n", i);
sleep(2);
}
void eat(int arga){
//printf("I am philosopher %d i am eating\n", i);
sleep(3);
}
int parent(void){
puts("This is the Parent Process");
int philosopherState;
char* philprint;
int count=0;
int c;
while (1){
sleep(1);
//sem_wait(&shared->mutex);
for(int o = 0; o<N;o++ ){
/*philosopherState = shared->state[o];
if (philosopherState == 0) {
philprint = "Thinking";
}else if(philosopherState == 1){
philprint = "Eating";
}else if(philosopherState == 2){
philprint = "Hungry";
}else if(philosopherState == 3){
philprint = "Gone";
count++;
}*/
sem_getvalue(&shared->s[o], &c);
//printf("P%d %s \t",o, philprint);
if (c==0){
printf("P%d Thinking\t",o);
}
else if(c==1){
printf("P%d Eating\t",o);
}
else if (c==2){
printf("P%d Hungry\t",o);
}
else if (c==3){
printf("P%d Gone\t",o);
}
if (count >4){
break;
}
}
//sem_post(&shared->mutex);
printf("\n");
}
return 0;
}
//while(count<5){
while(1){
//sleep(1);
//think(i);
take_forks(arga);
sleep(2);
//eat(i);
//sleep(1);
put_forks(arga);
//count++;
}
shared->state[arga] = FINISH;
}
void take_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga take_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutex */
shared->state[arga] = HUNGRY; /* record fact that philosopher i is hungry */
//while (shared->state[i] == HUNGRY){
test(arga); /* try to acquire 2 forks */
sem_post(&shared->mutex); /* exit critical region, up mutex */
//sem_wait(&shared->s[arga]); /* block if for ks were not acquired, down philosopher*/
//}
//sleep(1);
}
void put_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga put_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutes */
//test(LEFT); /* see if left neighbor can now eat */
//test(RIGHT); /* see if right neighbor can now eat */
shared->state[arga] = THINKING; /* philosopher has finished eating */
sem_post(&shared->mutex); /* exit critical region, up mutex */
}
void test(int arga) /* i: philosopher number, from 0 to N−1 */
{
sem_wait(&shared->s[LEFT]);
sem_wait(&shared->s[RIGHT]);
shared->state[arga]= EATING;
sleep(1);
sem_post(&shared->s[RIGHT]);
sem_post(&shared->s[LEFT]);
//if (shared->state[arga] == HUNGRY && shared->state[LEFT] != EATING && shared->state[RIGHT] != EATING)
//{
//printf("Philosopher: %d (i+N-1)%N - %d", i, ((i+N-1)%N));
//shared->state[arga] = EATING;
//sleep(2);
//sem_post(&shared->s[arga]); //Up philosopher
//}
}
void think(int arga){
//printf("I am philosopher %d i am thinking\n", i);
sleep(2);
}
void eat(int arga){
//printf("I am philosopher %d i am eating\n", i);
sleep(3);
}
int parent(void){
puts("This is the Parent Process");
int philosopherState;
char* philprint;
int count=0;
//int c;
while (1){
sleep(1);
for(int o = 0; o<N;o++ ){
philosopherState = shared->state[o];
if (philosopherState == 0) {
philprint = "Thinking";
}else if(philosopherState == 1){
philprint = "Eating";
}else if(philosopherState == 2){
philprint = "Hungry";
}else if(philosopherState == 3){
philprint = "Gone";
count++;
}
//sem_getvalue(&shared->s[o], &c);
printf("P%d %s \t",o, philprint);
//printf("P%d %s\t",o, c == 0 ? "Eating" : "Hungry");
if (count >4){
break;
}
}
printf("\n");
}
return 0;
}
When the thread goes to perform_work() to make a new pid, it spits out a segmentation fault when it tries to do it a second time. I must be configuring my thread creation wrong but I'm not sure where. This question is a follow up to: Modify PID manager for multi-threading
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#define MIN_PID 300
#define MAX_PID 5000
#define CB CHAR_BIT
#define NUM_THREADS 20
int sz = MAX_PID - MIN_PID + 1;
int id;
int i;
int map;
unsigned char *unsignedChar;
int allocate_map();
int allocate_pid();
void *perform_work();
void release_pid(int pid);
int main()
{
pthread_t threads[NUM_THREADS];
int thread_args[NUM_THREADS];
int result_code, index;
//create all threads one by one
for (index = 0; index < NUM_THREADS; ++index){
thread_args[index] = index;
printf("Creating thread %d\n", index);
result_code = pthread_create(&threads[index], NULL, perform_work(), (void *) &thread_args[index]);
assert(0 == result_code);
}
// wait for each thread to complete
for (index = 0; index < NUM_THREADS; ++index) {
// block until thread 'index' completes
result_code = pthread_join(threads[index], NULL);
printf("In main: thread %d has completed\n", index);
assert(0 == result_code);
}
printf("In main: all threads completed successfully\n");
//release a few processes
release_pid(303); printf("\nProcess 303 released.");
release_pid(308); printf("\nProcess 308 released.");
release_pid(309); printf("\nProcess 309 released.");
//allocate a few more processes after this release
int val = allocate_pid(); printf("\nProcess %d : pid = %d", ++i, val); //should be 303
val = allocate_pid(); printf("\nProcess %d : pid = %d\n", ++i, val); //should be 308
}
void *perform_work(void *argument){
map = allocate_map();
i = 0;
id = 0;
if (map == 1) {
printf("\nBitmap Data Structure initialized.\n");
int val = allocate_pid();
printf("\nProcess %d: pid = %d\n", i+1, val);
i++;
}
else printf("\nFailed to initialize data structure.\n");
}
/* Creates and initializes a bitmap data structure for representing pids;
returns —1 for unsuccessful, 1 for successful */
int allocate_map() {
unsignedChar = (unsigned char*)malloc((sz+CB-1)/CB * sizeof(char));
if (unsignedChar) return 1;
return -1;
}
/* Allocates and returns a pid; returns -1
if it is unable to allocate a pid (all pids are in use) */
int allocate_pid() {
int i = 0;
int pid = unsignedChar[i/CB] & (1 << (i & (CB-1)));
while (pid != 0) {
i++;
pid = unsignedChar[i/CB] & (1 << (i & (CB-1)));
}
if (i+MIN_PID > MAX_PID) return -1;
unsignedChar[i/CB] |= 1 << (i & (CB-1));
return i+MIN_PID;
}
/* Releases a pid given a pid parameter*/
void release_pid(int pid) {
if (pid < 300) {
printf("\nInvalid PID: It should lie between 300 and 3000.");
return;
}
int i = pid - MIN_PID;
unsignedChar[i/CB] &= ~(1 << (i & (CB-1)));
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<errno.h>
int main(int argc, char **argv){
int n = atoi(argv[1]);
int superdaddy = getpid();
int p[n+1][2];
int i=0;
int cpid,output;
int result = 0;
if(pipe(p[0])<0){
perror("1");
return 1;
}
if(pipe(p[n])<0){
perror("2");
return 1;
}
output = p[0][1];
if(getpid()==superdaddy){
if(write(p[0][1],&result,sizeof(result))<0){
perror("3");
return 1;
}
if(close(p[0][1])<0){
perror("4");
return 1;
}
}
while(1){
if(i==n){
if(read(p[n-1][0],&result,sizeof(result)<0)){
perror("5");
return 1;
}
result++;
output = p[n][1];
if(write(output,&result,sizeof(result))<0){
perror("6");
return 1;
}
if(close(p[n-1][0])<0){
perror("7");
return 1;
}
if(close(p[n][1])<0){
perror("8");
return 1;
}
break;
}
i++;
cpid = fork();
if(cpid==0){
if(i==n)
continue;
if(pipe(p[i])<0){
perror("9");
return 1;
}
if(read(p[i-1][0],&result,sizeof(result))<0){
perror("10");
return 1;
}
result++;
output = p[i][1];
if(write(output,&result,sizeof(result))<0){
perror("11");
return 1;
}
if(close(p[i-1][0])<0){
perror("12");
return 1;
}
if(close(p[i][1]<0)){
perror("13");
return 1;
}
continue;
}
else if(cpid<0){
perror("14");
return 1;
}
break;
}
if(getpid()==superdaddy){
wait(NULL);
if(read(p[n][0],&result,sizeof(result))<0){
perror("15");
return 1;
}
printf("Result: %d\n",result);
if(close(p[n][0])<0){
perror("16");
return 1;
}
}
return 0;
}
The Program aims to read a number n from command line and then forks n child process and create n pipes. process p0 will be parent of process p1, p1 will be parent of p2, so and so on. One variable (named result here) will be passed through pipes, every time it is passed it will be added by 1. So the output should be n as well. Pipe Fi connects Pi and P(i+1). Attached is my code.
When n=1 or n=2, the program can output correctly, which is 1 and 2 correspondingly. However, when n=3, it gives me a bad file error at error 5. I have hand-tracked the code for the whole afternoon but got no idea what is wrong with it. Anyone could help? Appreciate it first!
when n=3, it gives me a bad file error at error 5.
This could be fixed by removing that if(close(p[i][1]<0)){ in your code, because you need to read from p[i][0] in your last iteration, i.e.
if (i == n) {
if(read(p[n-1][0],&result,sizeof(result)<0)){
...
}
}
This is an implementation of your idea, I hope it may be helpful:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s N\n", argv[0]);
exit(EXIT_FAILURE);
}
int n = atoi(argv[1]);
int pipes[n][2];
int i, val;
pid_t pid;
val = 0;
for (i = 0; i < n; i++) {
if (pipe(pipes[i]) < 0) {
perror("pipe");
exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
else if (pid == 0) {
close(pipes[i][1]);
if (read(pipes[i][0], &val, sizeof(val)) != sizeof(val)) {
perror("read");
exit(EXIT_FAILURE);
}
printf("C %d read %d\n", getpid(), val);
val++;
}
else {
close(pipes[i][0]);
printf("P %d writes %d\n", getpid(), val);
if (write(pipes[i][1], &val, sizeof(val)) != sizeof(val)) {
perror("write");
exit(EXIT_FAILURE);
}
if (waitpid(pid, NULL, 0) != pid) {
perror("waitpid");
exit(EXIT_FAILURE);
}
printf("%d is going to leave.\n", getpid());
exit(EXIT_SUCCESS);
}
}
printf("%d is going to leave.\n", getpid());
exit(EXIT_SUCCESS);
}
Testing run:
$ ./a.out 3
P 2005 writes 0
C 2006 read 0
P 2006 writes 1
C 2007 read 1
P 2007 writes 2
C 2008 read 2
2008 is going to leave.
2007 is going to leave.
2006 is going to leave.
2005 is going to leave.
Explanation:
The frame of that code is for (i = 0; i < n; i++) { pipe(); fork(); }, which means it will create n pipes, and n new processes. In each iteration, the parent will write to pipes[i][1] and child will read from pipes[i][0]. Eventually, it will create a process chain connected by a series of pipes, and a value is passed down from the first process to the last through that series of pipes.