The code doesn't work and it goes in loop. I think the error is in the gestore method, that is a handler for SIGCHLD signals. This is the first time I use a handler to capture SIGCHLD signals.
This program continue to casually extracts from 0 to argv[1] until a number appears argv[1] times.
If it's not clear you can test my old program that I put at the end of question.
Can you help me finding the error?
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int a;
void gestore(int segnale);
int main(int argc, char * argv[]){
int n = atoi(argv[1]), i, pid;
int * vec;
vec = malloc((n+1)*sizeof(*vec));
memset (vec, 0, sizeof(*vec));
char * newargv[] = {argv[0], argv[1] , NULL};
for(i = 0; i < n; i++){
pid = fork();
if (pid == 0)
execve("./throw-dice", newargv, NULL);
signal(SIGCHLD, gestore);
vec[WEXITSTATUS(a)]++;
}
while(vec[i] != n){
for(i = 1; i < n+1 && vec[i] != n; i++){
if(vec[i] != 0){
pid = fork();
if (pid == 0)
execve("./throw-dice", newargv, NULL);
signal(SIGCHLD, gestore);
vec[WEXITSTATUS(a)]++;
}
}
}
printf("The value %d is appeared %d times!\n", i, vec[i]);
while (wait(&a) != -1);
free(vec);
}
void gestore(int segnale){
signal(segnale, SIG_IGN);
waitpid(WAIT_ANY, &a, WNOHANG);
signal(segnale, gestore);
}
My goal was to modify my old program (that works) changing the way I capture the exit status of childs. From syncronically with "wait" to asyncronically with a gestore method that handle SIGCHLD signals.
This is my old program:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char * argv[]){
int n = atoi(argv[1]), a, i, pid;
int * vec;
vec = malloc((n+1)*sizeof(*vec));
memset (vec, 0, sizeof(*vec));
char * newargv[] = {argv[0], argv[1] , NULL};
for(i = 0; i < n; i++){
pid = fork();
if (pid == 0)
execve("./throw-dice", newargv, NULL);
wait(&a);
vec[WEXITSTATUS(a)]++;
}
while(vec[i] != n){
for(i = 1; i < n+1 && vec[i] != n; i++){
if(vec[i] != 0){
pid = fork();
if (pid == 0)
execve("./throw-dice", newargv, NULL);
wait(&a);
vec[WEXITSTATUS(a)]++;
}
}
}
printf("The value %d is appeared %d times\n", i, vec[i]);
while (wait(&a) != -1);
free(vec);
}
//throw-dice.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
int n, val;
// Must have an argument
if (argc < 2) {
exit(-1);
}
// the 1st argument must be a positive number
if ((n = atoi(argv[1])) <= 0) {
exit(-1);
}
// sleep(1); // sleep a bit
srand(getpid()); // initialize the random seed with PID
val = rand() % n + 1;
printf("(PID=%d): got number %d\n", getpid(), val);
exit(val);
}
Related
I am new to parallel processing and was attempting to use fork() to create a new child process where I would like to overlay this process by using execve. It happened to me that execve("_filename",array, NULL) sometimes works but most of the time, it failed to overlay the process and return -1; I tried to run other's sample code but it failed on my laptop so I am wondering if this is because of my mac's configuration? I am really new to this topic and hope I can find help here, thanks!
Here is the program I am attempting to run:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
int main(int argc, char **argv) {
// populate arraay with random numbers
int child_status;
pid_t pid;
int i;
pid = fork();
char *array[3] = {"Hello", "There", "Test"};
if (pid == 0) {
pid = execve("Process4", array, NULL);
exit(0);
}
int num = -1;
printf("What is 2 + 2");
while (num != 4) {
scanf("%d", &num);
if (num == 4) {
printf("You win \n");
} else {
printf("%i incorrect - try again ", num);
printf("\r\b\r");
}
}
wait(&child_status);
return (0);
}
And for Process4, I wrote below:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int secs = 0;
int main(int argc, char **argv) {
int i;
if (argc > 0) {
printf("The arguments supplied are:\n");
for (i = 0; i < argc; i++) {
printf("%s\t", argv[i]);
}
} else {
printf("argument list is empty.\n");
}
int j;
printf("\n");
while (secs < 10) {
printf("Time:%i\n", secs);
fflush(0);
sleep(1);
secs++;
printf("\r\b\r");
}
return 0;
}
My process4 should be able to receive the parameters passed in (as an array in the second argument) and start the timer.
Thanks in advance for the help.
The array to specify the arguments for execve() must be terminated by NULL.
Try
char *array[] = {"Hello", "There", "Test", NULL};
instead of
char *array[3] = {"Hello", "There", "Test"};
So I have three files: Pellets.c, Fish.c, and SwimMill.c. SwimMill calls Pellets and Fish, which should fork. However, when I try to fork Pellets, i get an error saying "Pellet fork failed: Bad Address". Anyone know what the problem is?
include.h
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#define SHM_SIZE 1000
int shmid;
int *shm;
pid_t fish;
pid_t pellet;
void attachSharedMemory() {
key_t key = ftok("SwimMill.c", 'b'); //generate random key
shmid = shmget(key, SHM_SIZE, IPC_CREAT|0666);
shm = shmat(shmid, NULL, 0);
}
SwimMill.c
// Uses both fish and pellets, 30 seconds, then print it out
// Create pellets at random intervals, from 0x80
// Eating --> Get rid of most significant bit
// Use shared memory for fish and pellet position only
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "include.h"
#define SHM_SIZE 1000
void printGrid(int*);
void handler(int);
void killProgram(pid_t, pid_t, int*, int);
pid_t fish;
pid_t pellet;
int main(int argc, char* argv[]) {
int timer = 0;
attachSharedMemory(); // from include.h
signal(SIGINT, handler);
// Initializing the shared memory to prevent segmentation fault
// for (int i = 0; i < SHM_SIZE; i++){
// shm[i] = -1;
// }
srand(time(NULL));
fish = fork();
if (fish == -1) {
perror("Fish fork failed1");
exit(1);
} else if (fish == 0) {
execv("Fish", argv);
perror("Fish exec failed");
exit(1);
}
while(timer <= 30){
pellet = fork();
if (pellet == -1) {
perror("Pellet Fork failed1");
exit(1);
} else if (pellet == 0) {
execv("Pellets", argv);
perror("Pellets Fork failed");
exit(1);
}
printGrid(shm);
sleep(1);
printf("Timer: %d\n", timer);
timer++;
}
killProgram(fish, pellet, shm, shmid);
getchar(); // Pause consol
return 0;
}
void printGrid(int* shm) {
int row = 10;
int column = 10;
char (*stream)[row][column]; //2D Dimensional array, fish can only move last row of 2d
//Initializing grid first
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
(*stream)[i][j] = '~';
}
}
printf("Fish: %d \n", shm[0]);
printf("Shm2 is: %d \n", shm[1] );
for (int k = 1; k < 20; k++) {
(*stream)[shm[k]/10][shm[k]%10] = 'O'; // pellets
}
(*stream)[shm[0]/10][shm[0]%10] = 'Y'; // Fish
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
printf("%c ", (*stream)[i][j]);
}
printf("\n");
}
}
void killProgram(pid_t fish, pid_t pellet, int *shm, int shmid) {
kill(fish,SIGUSR1);
kill(pellet, SIGUSR1);
sleep(5);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
printf("Program finished! \n");
}
void handler(int num ) {
kill(fish,SIGUSR1);
kill(pellet, SIGUSR1);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
perror(" Interrupt signal is pressed!! \n");
exit(1);
}
Pellets.c
// Multiple pellets
//Process ID, position, eaten/misse
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "include.h"
#define SHM_SIZE 1000
void handler(int);
void eatPellet();
void missPellet();
int main(int argc, char* argv[]) {
signal(SIGINT, handler);
attachSharedMemory();
srand(time(NULL));
int i = 1; // 1 - 19 are pellets
for (; i < 20; i++) {
int pelletPosition = rand() % 9 ; // random number from 0 - 9
if (shm[i] == -1){
// printf("hello %d \n", pelletPosition);
shm[i] = pelletPosition;
}
break;
}
while(1) {
printf("helloasd %d \n", shm[i]);
printf("i: %d \n", i);
if (shm[i] < 90) {
shm[i] += 10;
}
else if (shm[i] == shm[0]) {
eatPellet();
printf("Position: %d\n", shm[i] );
break;
// EATEN and KILL
}
else {
// KIll process, terminate
missPellet();
printf("Position: %d\n", shm[i] );
break;
}
// printf("%d\n",shm[i] );
i++;
sleep(1);
}
shmdt(shm);
return 0;
}
void handler(int num) {
shmdt(shm);
exit(1);
}
I looked at other stack overflow questions, and it seems that they problems because they didn't terminate with a NULL? I think the problem lies inside Pellets.c, but I can't seem to figure it out. Thanks.
The program has to do it:
A process P0 creates P1 and P2;
sizeof(buffer) = N (inserts with command line);
P1 inserts random values in the first N/2 elements of the buffer (N insert by user)
P2 inserts random values in the second part of the buffer
After that: P1 inverts the second part of the buffer and then the process P0 print all elements of it
If the user presses CTRL+C ---> print the buffer elements and kill all process;
I don't know why , but process P1 remains in pause. I called in the concurrent process P2 the increase of the semaphore's value ("semaphore_inv") and the wait has to decrease it to 0. For this reason the program doesn't work correctly.
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
int N;
int buff[1024];
void print(int sig) {
int i;
for(i=0; i<N; i++) {
printf("Slot %d of the buffer is %d\n",i, buff[i]);
}
kill(0,SIGKILL);
}
void main (int argc, char* argv[]) {
int p1, p2;
sem_t semaphore_inv;
sem_t semaphore_read;
sem_t semaphore_write;
struct sembuf sembuf;
N=atoi(argv[1]);
if (N<=0 || N>=1024) {
printf("Inserirt a value > 0 and < 1024\n");
exit(-1);
}
if (argc!=2) {
printf("Insert com N\n");
exit(1);
}
int buffer[N];
//I insert this type of semaphore only to try it
int sem_write = semget(IPC_PRIVATE,1,IPC_CREAT|0666);
if (sem_write <0) printf("Error in the semaphore creation\n");
int sem_write_b = sem_init(&semaphore_write,1,1);
if (sem_write_b<0) printf("Error in the semaphore creation\n");
int sem_inv = sem_init(&semaphore_inv, 1, 0);
if (sem_inv<0) printf("Error in the semaphore creation\n");
int sem_read = sem_init(&semaphore_read,1,0);
if (sem_read<0) printf("Error in the semaphore creation\n");
int ret = semctl(sem_write, 0, SETVAL, 1);
if (ret == -1) printf("Error: semctl, with errno %s\n", strerror(errno));
signal(SIGINT, print);
p1 = fork();
p2 = fork();
if (p1 < 0) {
printf("P1: error, fork\n");
exit(-2);
}
if (p2 < 0) {
printf("P2: error, fork\n");
exit(-2);
}
if (p1==0) {
loop:
sembuf.sem_num=0;
sembuf.sem_op= -1;
sembuf.sem_flg=0;
semop(sem_write, &sembuf, 1);
int i;
for (i=0; i<N/2; i++) {
buffer[i] = rand();
printf("P1: the insert value in buffer[%d] is %d\n",i , buffer[i]);
}
sem_wait(&semaphore_inv);
printf("P1: i'm going to invert the second part of the buffer\n");
int j=1;
for (i=N/2; i<N; i++){
int buffer_prev;
buffer_prev=buffer[i];
buffer[i] = buffer[N-j];
buffer[N-j] = buffer_prev;
j++;
}
sem_post(&semaphore_read);
sleep(1);
goto loop;
}
if (p2==0) {
loop_b:
sem_wait(&semaphore_write);
int i;
for (i=N/2; i<N; i++) {
buffer[i] = rand();
printf("P2: the value insert in buffer[%d] is %d\n", i, buffer[i]);
}
sem_post(&semaphore_inv);
sleep(1);
goto loop_b;
}
else{
sem_wait(&semaphore_read);
int k;
for (k=0; k<N; k++) {
buff[k] = buffer[k];
printf(" slot %d of the buffer is %d\n", buffer[k]);
}
sem_post(&semaphore_write);
sembuf.sem_num=0;
sembuf.sem_op= +1;
sembuf.sem_flg=0;
semop(sem_write, &sembuf, 1);
}
}
There are four processes involved. Illustration:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int pid = -2, pid1 = -2, pid2 = -2;
pid1 = fork();
pid2 = fork();
mypid = getpid();
printf("Pid= {%d, %d %d}\n", mypid, pid1,pid2);
return 0;
}
I'm taking a look at a Solution Example for Producer & Consumer problem, using pipes.
And I do not understand how it is preventing a race condition.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
void producer(FILE *pipe_write_end)
{
int i;
for(i = 1; i <= 10; i++) {
fprintf(pipe_write_end, "%d ", i);
}
fclose(pipe_write_end);
exit(0);
}
void consumer(FILE *pipe_read_end)
{
int n,k;
while(1) {
int n = fscanf(pipe_read_end, "%d", &k);
if(n == 1) printf("consumer: got %d\n", k);
else break;
}
fclose(pipe_read_end);
exit(0);
}
int main()
{
pid_t producer_id, consumer_id;
int pd[2];
FILE *pipe_write_end, *pipe_read_end;
pipe(pd);
pipe_read_end = fdopen(pd[0], "r");
pipe_write_end = fdopen(pd[1], "w");
producer_id = fork();
if(producer_id == 0) {
fclose(pipe_read_end);
producer(pipe_write_end);
}
consumer_id = fork();
if(consumer_id == 0) {
fclose(pipe_write_end);
consumer(pipe_read_end);
}
fclose(pipe_read_end);
fclose(pipe_write_end);
wait(NULL);
wait(NULL);
return 0;
}
My current thinking is that the int n = fscanf(pipe_read_end, "%d", &k); is waiting for the producer to close the file, but I don't understand how.
If 2 Child Processes are created, 1 to consume, 1 to Produce
- How is it able to automatically just produce without error?
This is bugging me for days.
The problem is my not so good understanding of pointers and addresses in c so i hope someone will be able to help me out.
I need to pass some strings as input parameters and create as much producer processes + one consumer process.
Producers should take the string apart and send each letter as message to queue. At the end it should send NULL("").
The consumer should wait for messages and print them out.
The whole code and output is below. By looking at the output i'd say that the problem is somewhere in the producer. To be more precise it is in the first line of te for loop but i can not get it right.
manager.c - This is the main program that operates processes
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/msg.h>
int main( int argc, char *argv[], char *envp[] ) {
printf("Starting %d processes \n", argc);
putenv("MSG_KEY=12345");
for (int i = 1; i < argc; i++) {
printf("argv[%d] = %s \n", i, argv[i]);
pid_t producer = fork();
if (producer == 0) {
printf("producer pid - %d\n", getpid());
execl("./producer", "producer", argv[i], NULL);
}
}
pid_t consumer = fork();
if (consumer == 0) {
printf("consumer pid - %d\n", getpid());
execl("./consumer", "consumer", NULL);
exit(0);
} else {
printf("manager pid - %d\n", getpid());
wait(NULL);
}
int status;
while(waitpid(consumer, &status, 0) == -1);
printf("DONE consumer\n");
printf("DONE manager\n");
return 0;
}
producer.c
/*
** writes to message queue
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msgbuf {
long mtype;
char mtext[1];
};
int main( int argc, char *argv[], char *envp[] ) {
struct my_msgbuf buf;
int msqid;
key_t key = atoi(getenv("MSG_KEY"));
if ((msqid = msgget(key, 0600 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
buf.mtype = getpid();
// I believe the error is in this for loop or to be more precise in the first line of the for loop.
// takes the first argument and sends characters in separate messages
for (int i = 0; i < strlen(argv[1]); ++i) {
char c = argv[1][i];
strcpy(buf.mtext, &c);
printf ("Sending -%s-\n", buf.mtext);
if (msgsnd(msqid, (struct msgbuf *)&buf, strlen(buf.mtext)+1, 0) == -1)
perror("msgsnd");
}
// send NULL at the end
memcpy(buf.mtext, "", strlen("")+1);
if (msgsnd(msqid, (struct msgbuf *)&buf, strlen("")+1, 0) == -1)
perror("msgsnd");
return 0;
}
consumer.c
/*
** reads from message queue
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msgbuf {
long mtype;
char mtext[1];
};
int main( int argc, char *argv[], char *envp[] ) {
struct my_msgbuf buf;
int msqid;
key_t key = atoi(getenv("MSG_KEY"));
if ((msqid = msgget(key, 0600 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
int flag = 0;
int wait_counter = 0;
while (wait_counter < 10) {
msgrcv(msqid, (struct msgbuf *)&buf, sizeof(buf)-sizeof(long), 0, flag);
if (errno == ENOMSG){
wait_counter++;
printf ("Sleaping for one second...zzzZZZzzz...%d\n", wait_counter);
usleep(1000 * 1000);
} else {
printf("Received:\n\ttype: -%ld- \n\tchar: -%s- \n", buf.mtype, buf.mtext);
int compare = strcmp(buf.mtext, "");
if(compare == 0){
printf("NULL received\n");
flag = IPC_NOWAIT;
} else {
flag = 0;
}
wait_counter = 0;
}
errno = 0;
}
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
} else {
printf("Message queue removed\n");
}
return 0;
}
Output - i have to give you the screenshot here because c/p deletes the problem and everything looks ok
Any help will be much appreciated! Thank you!
Error when used as suggested in the #sergeya answer below
*buf.mtext = c;
Your problem (one of them, at least) is here:
char c = argv[1][i];
strcpy(buf.mtext, &c);
strcpy() will try to copy as many characters as there are until nul-terminator '\0' is encountered, starting from c. You need to copy one character exactly, so you just need
*buf.mtext = c;
As i said, the problem was in the producer inside the for loop. I will put the change here. Hope it helps anyone with the similar problem.
#SergeyA gave me excellent clue where the problem is so i switched from "strcpy" to "memcpy" and i have copied just the first character and not the nul-terminator.
Also i have changed the "strlen" to "sizeof" and removed the +1.
Producer.c
...
for (int i = 0; i < strlen(argv[1]); ++i) {
char c = argv[1][i];
memcpy(buf.mtext, &c, sizeof(&c)+1);
printf ("Sending -%c-\n", buf.mtext);
if (msgsnd(msqid, (struct msgbuf *)&buf, sizeof(buf.mtext), 0) == -1)
perror("msgsnd");
}
...