I have the following code. It generates n child and then a random number between 0 and n. So that random number lets suppose is "i". The child number i must kill his brothers.
The problem is that the kill function is not killing anything since both ptree after and before are exactly the same.
I cant found a solution, the output must be the father and the i child only since all his brothers were killed by him.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
char archSalidaAntes[] = "aprocesosAntes.txt";
char archSalidaDespues[] = "aprocesosDespues.txt";
void imprimirArreglo(int arr[], int n){
int i;
for(i=0; i<n; i++){
printf("%d\t", arr[i]);
}
printf("\n");
}
void imprimirArbolTxt(char nombreArchivo[], pid_t id){
char buff[255];
sprintf(buff, "pstree -p -c -l %d > %s", (int)id, nombreArchivo);
system(buff);
}
void communicateSon(int arrProc[], int n, int fd[]){
int i;
int data;
int writeResp;
close(fd[0]); //closing input
for(i=0; i<n; i++){
data = arrProc[i];
writeResp = write(fd[1], &data, sizeof(data));
if(!writeResp){
printf("error writing");
}
}
close(fd[1]); //closing output
}
void killOthers(int n, int fd[], int randInt){
int i;
int readResp;
int killResp;
int data;
int arrProc[n];
close(fd[1]); //closing output
i = 0;
while(1){
readResp = read(fd[0], &data, sizeof(data));
fflush(stdout);
fflush(stdin);
if(!readResp){
break;
}
arrProc[i] = data;
i++;
}
imprimirArreglo(arrProc, n);
printf("id elegido: %d\n", getpid());
for(i=0; i<n; i++){
if(i!= randInt){
printf("killing: %d\n", arrProc[i]);
killResp = kill((pid_t)arrProc[i], SIGKILL);
if(killResp < 0){
printf("error kill: %d \n", killResp);
}
int aux = kill(arrProc[i], 0);
printf("aux: %d\n", aux);
}
}
close(fd[0]); //closing input
char com[30];
sprintf(com, "pstree -p %d", getppid());
system(com);
}
int main(int argc, char **argv){
int n;
int i;
int *arrProc;
int randInt;
int fd[2];
pid_t pId;
n = atoi(argv[1]);
printf("n = %d\n", n);
srand(time(NULL));
arrProc = (int*) malloc(sizeof(int) * n);
randInt = rand() % n;
pipe(fd);
for(i=0; i<n; i++){
pId = fork();
if(pId){
arrProc[i] = (int)pId;
if(i == (n-1)){
char com[30];
sprintf(com, "pstree -p %d", getppid());
system(com);
communicateSon(arrProc, n, fd);
waitpid(arrProc[randInt], NULL, 0);
printf("termino la espera del hijo\n");
free(arrProc);
}
} else if(pId == 0){ //hijos
if(i==randInt){
killOthers(n, fd, randInt);
exit(0);
} else{
break;
}
}
}
sleep(0.5);
return 0;
}
Since main process never calls waitpid for other children all of them become zombies after getting killed.
Update: you should also close pipe ends descriptors in other child processes prior to putting them to sleep, otherwise killer child process will get stuck at waiting for more data to come from the pipe.
} else{
close(fd[0]);
close(fd[1]);
break;
}
Update: sleep takes unsigned int number of seconds, so sleep(0.5) will be equivalent to sleep(0).
Try with sleep(1).
The sleep() function wants an integer argument, so sleep(0.5) equals to zero - which is probably not "long enough" for your demo to work. The child processes may terminate before the kill signal can reach them.
Related
This is my code system call in C.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int n;
int i;
pid_t pid;
int time = 1000;
int sum = 0;
int main(void) {
printf("n: ");
scanf("%d", &n);
pid = fork();
if (pid < 0) {
printf("Fork Failed");
exit(-1);
} else if (pid == 0) {
//child
for (i = 1; i <= n; i++) {
sum += i;
}
printf("Sum of 1 to %d: %d\n", n, sum); // this is ok
} else {
// parent
wait(&time);
printf("Sum of 1 to %d: %d\n", n, sum); // this always return 0;
}
return 0;
}
I don't know why in parent's code block, the sum is always equal to 0.
How to make parent wait for child or am I doing something wrong ?
Waiting for the child works. However, your expectations are wrong.
Apparently you think that computations in the child process after the fork are visible in the parent process. They are not. The child is a new copy of the parent program at the time of fork. At that time, the parent's sum is 0 and stays that way.
There are several mechanisms to pass data from child to parent (the search term is interprocess communication, IPC).
exit() status
files
shared memory
pipes
signals
message queues
anything else I have missed
The issue here is the variable sum is not shared by the parent & child process, after fork() call the child will have its own copy of the variable sum.
Use shmget(),shmat() from POSIX api. Or use pthread which will share the same memory space for the newly created thread.
Update---
Added the shared memory to your code hopes this helps.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/shm.h>
int n;
int i;
pid_t pid;
int time = 1000;
int main(void) {
int shmid;
int *sum;
printf("n: ");
scanf("%d", &n);
/*request the shared memory from the OS using the shmget()*/
shmid = shmget(IPC_PRIVATE, sizeof(int), 0777|IPC_CREAT);
pid = fork();
if (pid < 0) {
printf("Fork Failed");
exit(-1);
} else if (pid == 0) {
//child
/* shmat() returns a char pointer which is typecast here
to int and the address is stored in the int pointer. */
sum = (int *) shmat(shmid, 0, 0);
for (i = 1; i <= n; i++) {
*sum += i;
}
printf("Sum of 1 to %d: %d\n", n, *sum); // this is ok
/* each process should "detach" itself from the
shared memory after it is used */
shmdt(sum);
} else {
// parent
wait(&time);
sum = (int *) shmat(shmid, 0, 0);
printf("Sum of 1 to %d: %d\n", n, *sum); // this always return 0;
shmdt(sum);
/*delete the cretaed shared memory*/
shmctl(shmid, IPC_RMID, 0);
}
return 0;
}
Refer for more info- https://man7.org/linux/man-pages/man2/shmget.2.html
I'm trying to create n child with the same parent, and send the random number from child -> parent.
For now, I have a problem to send random 0/1 from child -> parent.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
pid_t pids[10];
int i;
int n = 10;
/* Start children. */
for (i = 0; i < n; ++i) {
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
} else if (pids[i] == 0) {
// printf("I am a child with id %d and my parent %d\n",getpid(),getppid());
int random = rand() % 2;
printf("\nChild send random: %d\n",random);
write(pids[1], &random, sizeof(random));
exit(0);
}
else{
int ran;
read(pids[0], &ran, sizeof(ran)); // read from child
printf("\nParent Received: %d\n", ran);
}
}
wait(NULL);
}
The problems are:
first, read and write don't want a pid like first argument but a file descriptor and second, for passing something between two processes you should use a IPC mechanism like pipes:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
int main()
{
pid_t pids[10];
int _pipe[2];
int i;
int n = 10;
int random;
srand(time(NULL));
/* Start children. */
for (i = 0; i < n; ++i) {
//printf("%d\n",i);
pipe(_pipe);
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
} else if (pids[i] == 0) { // Child
random = rand() % 2;
char str[2];
sprintf(str,"%d",random);
//printf("\nChild send random: %d\n",random);
close(_pipe[0]);
write(_pipe[1], str, sizeof(str));
printf("Pipe sended: %s\n",str);
exit(0);
}
else{ // Parent
char string[1];
close(_pipe[1]);
read(_pipe[0],string,sizeof(string)); // read from child
printf("pipe received: %s\n",string);
//printf("\nParent Received: %d\n", ran);
}
}
wait(NULL);
}
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 supposed to return the sum of first 12 terms of Fibonacci series from child process to parent one but instead having 377, parent gets 30976.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t childpid;
int i, fib_sum=0, fib1=1, fib2=1, temp, status;
childpid=fork();
if(childpid!=0)
{
wait(&status);
fprintf(stderr, "%d\n", status);
}
else
{
for(i=1; i<=12; i++)
{
temp=fib1;
fib_sum=fib1+fib2;
fib1=fib_sum;
fib2=temp;
}
fprintf(stderr, "%d\n", fib_sum);
return fib_sum;
}
}
What am I doing wrong?
I'm supposed to return the sum of first 12 terms of Fibonacci series
from child process to parent one but instead having 377, parent gets
30976.
Process exit status is limited in value, therefore it is not the best way to communicate a value between child and parent.
One of the solution is to pass the calculated value using pipes.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t childpid;
int i, fib_sum=0, fib1=1, fib2=1, temp, status;
int fd[2];
int val = 0;
// create pipe descriptors
pipe(fd);
childpid = fork();
if(childpid != 0) // parent
{
close(fd[1]);
// read the data (blocking operation)
read(fd[0], &val, sizeof(val));
printf("Parent received value: %d\n", val);
// close the read-descriptor
close(fd[0]);
}
else // child
{
// writing only, no need for read-descriptor:
close(fd[0]);
for(i=1; i<=12; i++)
{
temp = fib1;
fib_sum = fib1+fib2;
fib1 = fib_sum;
fib2 = temp;
}
// send the value on the write-descriptor:
write(fd[1], &fib_sum, sizeof(fib_sum));
printf("Child send value: %d\n", fib_sum);
// close the write descriptor:
close(fd[1]);
return fib_sum;
}
}
Test:
Child send value: 377
Parent received value: 377
If you can't use pipes, which would be the optimal solution here, you could save the result to a file that the parent would read from. Pass the name of the file to save the result to from parent to child. In your child process, you would do:
int main(int argc, char *argv[])
{
int fib_sum=0;
if (argc <= 1)
{
print_usage();
return 1;
}
//... calculate fib_sum
FILE *f = fopen(argv[1], "w");
if (f == NULL)
{
printf("Error opening file!\n");
return 1;
}
fprintf(f, "%d", fib_sum);
return 0;
}
Then in your parent process:
int n = 0;
FILE* f;
//... spawn child and wait
FILE *f = fopen(file_name, "r");
fscanf(f, "%d", &n);
Source Code:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main(){
int fd1[2];
int sample[] = {1,2,3,4};
int input[] ={5 , 6, 7,8};
pid_t p;
if (pipe(fd1)==-1)return 1;
if (pipe(fd2)==-1) return 1;
write(fd1[1], input, sizeof(input)+1);
write(fd1[1], sample, sizeof(sample)+1);
close(fd1[1]);
char concat[100];
read(fd1[0],concat,100);
int i=0;
for(i;i<sizeof(concat);i++){
printf("%i ",concat[i]);
}
printf("\n");
}
I want to write arrays in on pipe, and after that i want to read out the first array only, not the whole pipe or not like in the code:
read(fd1[0],concat,100);
Is this possible? If it's not I will use structs.
Concatenating two array of int via pipe.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
int fd1[2];
int fd2[2];
int sample[] = {1,2,3,4};
int input[] ={5 , 6, 7,8};
pid_t p;
if (pipe(fd1)==-1)return 1;
if (pipe(fd2)==-1) return 1;
p = fork();
if (p < 0) return 1;
// Parent process
else if (p > 0)
{
int concat[100];
close(fd1[0]);
write(fd1[1], input, sizeof(input)+1);
close(fd1[1]);
wait(NULL);
close(fd2[1]);
read(fd2[0], concat, 100);
printf(" %i", concat[0]);
printf(" %i", concat[1]);
printf(" %i", concat[2]);
printf(" %i", concat[3]);
close(fd2[0]);
}
// child process
else
{
close(fd1[1]);
char concat[100];
read(fd1[0], concat, 100);
int k = sizeof(concat);
int i;
for (i=0; i<sizeof(sample); i++)
concat[k++] = sample[i];
concat[k] = '\0';
close(fd1[0]);
close(fd2[0]);
write(fd2[1], concat, sizeof(concat)+1);
close(fd2[1]);
exit(0);
}
}