I have to create prog1 which take one argument with number of children have to create. (example "./prog1 5" - will create 5 children) Each of children will generate random number from 1 to 20. This number will be given to execl which will start prog2 (in same folder) which take as a argument this random number. Prog2 should sleep this random number time. After that it should return this random number to parent.
I created something like this but it still don't work properly.
prog1:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int n, i, pid;
int u = getppid();
int procesy = 0;
pid_t proc_id;
n = atoi(argv[1]);
for(i = 0; i < n; i++)
{
proc_id = fork();
if(proc_id==0)
{
srand(getpid());
u = 1 + rand()%20;
execl("./prog2", "prog2", u,0);
}
else
{
procesy++;
}
}
if(u == getppid())
{
for(i = 0; i < n; i++)
{
pid = wait(&u);
printf("Process %d ende\n", pid);
procesy--;
}
if(procesy == 0) printf("endc\n");
}
return 1;
}
prog2:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int n;
n = atoi(argv[1]);
sleep(n);
exit(n);
}
Change your loop to look something like the following, in order to properly call execl():
if(proc_id==0)
{
char arg[16];
srand(getpid());
sprintf(arg, "%d", 1 + rand()%20);
execl("./prog2", "prog2", arg, 0);
printf("I should not be here!\n");
exit(-1);
}
Then get rid of if(u == getppid()) (but keep the contents of the conditional). It seems with that if you were trying to filter out the child from running that block. When execl() works, the child is not going to run anything in this code after the execl()... the printf and exit I added will not be run. Those lines will only run if execl() fails, and in this simple case, the only way it will fail is if you've provided improper arguments.
Related
I am doing a for loop to create children with fork and print their pids, but instead of printing them in order it mixes them up.! what it prints :
[PARENT/PID=953] Created child 0 [PID=954] and initial state f
[PARENT/PID=953] Created child 3 [PID=957] and initial state f
[PARENT/PID=953] Created child 2 [PID=956] and initial state t
[PARENT/PID=953] Created child 1 [PID=955] and initial state f
also prints in other orders
tried to put wait(&status) in different places but it didnt help.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define PERMS 0644
int main(int argc, char **argv) {
int n = strlen (argv[1]);
int status;
for(int i=0;i<n;i++) // loop will run n times
{
if(fork() == 0)
{
char s[5];
sprintf(s, "%c", argv[1][i]);
char *const argv2[] = {"./child.c",s,NULL};
wait(&status);
status = execv("./child", argv2);
printf("[PARENT/PID=%d] Created child %d [PID=%d] and initial state %s \n",getppid(),i,getpid(),s);
exit(0);
}
}
for(int i=0;i<n;i++) // loop will run n times
wait(NULL);
}
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"};
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?
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);
}
I already used execl() in code, and it worked well.
But this time, I really have no idea why it doesn't work.
So here's the code that do not work
#include <unistd.h>
#include <stdio.h>
int main()
{
int i = 896;
printf("please\n");
execl("home/ubuntu/server/LC/admin/admin", (char*)i, NULL);
printf("i have no idea why\n");
return 0;
}
And here's the admin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int mid = argv[0];
printf("hi from child\n");
printf("%d\n", mid);
return 0;
}
Of course I compiled admin.c to admin, and the path isn't wrong.
>ls
admin admin.c why why.c
>pwd
/home/ubuntu/server/LC/admin
>./admin
hi from child
-1180858374
>./why
please
i have no ida why
Anyone know why it doesn't work?
My C is a bit rusty but your code made many rookie mistakes.
execl will replace the current process if it succeeds. So the last line ("i have no idea why") won't print if the child can launch successfully. Which means...
execl failed and you didn't check for it! Hint: check the typecast to char *.
You cast an int to a char * in the execl call, then again when you launch the child (admin). This is a big no-no in C. It freely allows you to misinterpret types. The only warning is most often a crash. GGC will warn you about it. I don't know about the compiler on AWS.
Check your array's bound! You don't know how many parameters admin was launched with. argv[0] always exist because it contains a representation of the program name. argv[1] may not be defined. Accessing array out-of-bound is an undefined behavior and highly dangerous.
The standard way to start another process in C is to fork the parent, then call one of the functions in the exec family to start the other process.
Consider this instead (I took the liberty to emit different messages to make them clearer).
parent.c
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
int i = 896;
char str[15];
int pid;
printf("Hello from parent\n");
sprintf(str, "%d", i); // convert the number into string
pid = fork();
if (pid == -1)
{
printf("Fork failed\n");
}
else if (pid == 0)
{
printf("Continue from parent\n");
}
else
{
// start the child process
execl("home/ubuntu/server/LC/admin/admin", str, NULL);
// check if it started properly
if (errno != 0)
{
printf("Error launching child process: %s\n", strerror(errno));
return 1;
}
}
printf("Goodbye from parent\n");
return 0;
}
admin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char * mid;
// argc is always 1 or more
if (argc >= 2)
mid = argv[1];
else
mid = "<nothing>";
printf("hello from child\n");
printf("argc = %d, argv[1] = %s\n", argc, mid);
return 0;
}