C - System Calls - Partition of array for N children processes - - c

First of all thank you for the help in advance. I have to write a program in which I pass an element to search from terminal and in which the parent process divides the array (consisting of random numbers) of dimensions - defined by terminal - in equal parts, each managed by a child process with the same code. Each child takes care of looking for the element in a part of the array, in order to divide fairly the job among the children processes.
The problem is that I don't know how to make this partition, without an array sorted. I thought I could do kind of Merge/Cocktail or Quick Sort,
but I think it is overabundant and useless for this task.
Here it is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
int partition(int x, int y);
int main(int argc, char*argv[]){
int i, j, result, state_wait, *v, n_children, dim, random_number;
int elem,div,lower,higher;
pid_t pid;
srand(time(NULL));
if(argc<4){
fprintf(stderr,"Insufficient parameters\n");
exit(EXIT_FAILURE);
}
n_children=atoi(argv[1]);
if(n_children<0){
fprintf(stderr,"Enter a positive number of children\n");
exit(EXIT_FAILURE);
dim=atoi(argv[2]);
if(dim<0||dim>n_children){
fprintf(stderr,"Enter a valid size\n");
exit(EXIT_FAILURE);
elem=atoi(argv[3]);
fprintf(stdout,"F: Father || PID = %d\n",getpid());
v=(int*)malloc(sizeof(int)*dim);
fprintf(stdout,"F: VECTOR:\n\n");
for(i=0;i<dim;i++){
v[i]=rand();
fprintf(stdout,"(%d) v[%d] number = %d\n",i,i,v[i]);
}
for(j=0;j<n_children;j++){
if(fork()==0){
fprintf("F: Child N. = %d || PID = %d\n",i,getpid());
div=partition(dim,n_children);
//lower=? j*div?
higher=lower+div-1; //except the final case when it is dim-1
result=search(lower,higher,&elem);
}
}
}
int partition(int x, int y){
int div=(x/y); //If I had a vector of 1000 elem., work on them must be fairly distributed among the children
//number of elements each group
if((x-div)>1)
div=(x/y)+1;
return div;
}
int search(int lower,int higher, int*elem){
int i;
for(i=lower;i<=higher;i++){
if(v[i]==elem){
fprintf(stdout,"Element found [position = %d]\n",i);
exit(1);
}
}
exit(-1);
}

I believe you can use file descriptors for communication between processes. This is called a pipe. After that, you can split the array into the number of child processes available, perhaps including the parent one. Store these split parts in the pipe that you created. Let the child process fetch for the element in the file descriptor! I don't think it matters if the array is sorted or not, the task is divided by N (if N is the number of children) anyway. Search for
man 2 pipe
in the linux (or MacOS) terminal for more information!

Related

How to shared memory with parent and child processes in c

I want to calculate the factorial with Shared memory and fork()parent and child processes.My problem is child process doesn't seems to work, I want to give a number from parent to child and after the child passes the result of factorial to the parent. But the result is same with the number I gave.
I was asked to use snprintf() orspritnf()or itoa() and atoi() in order to pass the variable to each process.
I reached the following:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <sys/shm.h>
int main(int argc , char *argv[])
{
int shmid,fid,status,x;
char *shm;
char *s;
int i,y,c;
key_t key=1990;
//create shared memory
shmid=shmget(1990,300,IPC_CREAT|0666);
fid=fork();
shm=shmat(shmid,NULL,0);
if(fid>0)//parent process
{
wait(&status);
s=shm;
printf("enter a number:");
scanf("%d",&x);
sprintf(s,"%d",x);//convert int to string
printf("factorial of number:%d is:%s\n",x,s);//result
shmdt(shm);
shmctl(shmid,IPC_RMID,0);
}else if(fid==0)//child process
{
shm=shmat(shmid,NULL,0);
c=atoi(s);//conver string to int
// calculate factorial
for(i=1;i<=c;i++)
{
y *=i;
}
return y;
sprintf(s,"%d",y);
shmdt(shm);
}
return 0;
}
You have:
if(fid>0)//parent process
{
wait(&status);
The first thing the parent process does is wait for the child to die. Only then does it ask for the number that should be the input to the calculation. This isn't going to work well.
You need the parent to ask for the number, write it into shared memory, and tell the child via some (other) IPC mechanism that the number is ready. The child should then wake up, read the number, do the calculation, and write the answer, then notify the parent it is done simply by exiting. Meanwhile, the parent can now wait for the child to complete, and then reads the answer from the shared memory.
Were it my code, I'd do the shmat() before calling fork(). As written, the child uses shmat() twice (once just after the fork(), once in the else if (fid == 0) code. That's not orthodox.
It's odd to create the key_t key = 1990; and then not use it. I don't see status and x being used either.
As a way of calculating factorials, this is preposterous. As an exercise in IPC and inter-process synchronization, it is a nice simple example.
Remember, 32-bit integers can only store values up to 12! while 64-bit integers can only store values up to 20!, so it is usually sensible just to create a table of factorials — or just calculate them on the fly. Or you need to use floating-point arithmetic; it takes a while to get out their range (somewhere less than 200!, IIRC).

Static variable in child process of fork

I understand that both parent and child in fork() are two separated processes, but I was trying to understand the behavior of a static variable when it's declared and initialized in the child. Consider this code please:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
static int z = 99;
void main(){
int x=99;
int pid;
pid = fork();
switch(pid){
case -1: printf("fork failed.");break;
case 0: printf("I am the Child[PID=%d].\n",getpid());
static int y=99;
x++;y++;z++;
printf("x=%d, y=%d, z=%d\n",x,y,z);break;
default: wait(NULL);
//int y = 99;
printf("Child has finished. I am the parent[PID=%d].\n",getpid());
printf("x=%d, y=%d, z=%d\n",x,y,z);
}
}
Output:
Why in parent printf statement the value of y is 99? although that the parent waited for the child to finish, and in the child the value of y is changed to 100 "y++" after it was set to 99.
This is because y exists in two separate processes, i.e. two separate virtual address spaces. Changing one process won't affect the other process.
Compare this with threads, where threads share the same process, i.e. the same virtual address space, change will be seen by all threads.
Static variables are initialized at load time (compile time), not at run time. In the fork(), the memory image is copied, including these initialized static vaiables. The child performs the increment, the parent not.

Risk of losing data when sending variables through pipe?

I have the following code:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h> // may not be needed
#include <sys/stat.h> // may not be needed
#include <stdlib.h>
#include <string.h>
typedef struct {
int pid;
char arg[100];
int nr;
} Str;
int main() {
int c2p[2];
pipe(c2p);
int f = fork();
if (f == 0) {
Str s;
s.pid = 1234;
strcpy(s.arg, "abcdef");
s.nr = 1;
close(c2p[0]);
write(c2p[1], &s, sizeof(Str));
close(c2p[1]);
exit(0);
}
wait(0);
close(c2p[1]);
Str s;
read(c2p[0], &s, sizeof(Str));
printf("pid: %d nr: %d arg: %s", s.pid, s.nr, s.arg);
close(c2p[0]);
return 0;
}
I have to say that it worked just fine until now (pid, nr and arg were never altered), but:
When the child process is done, is the memory segment (used by the child) destroyed (marked as free)?
If so, is there the risk that between the time of writing and the time of reading to lose the acces to that segment or the data to be altered?
(The original question was this: Sending structure through pipe without losing data )
Although the child process' memory is given back to the operating system when the process exits, I suspect this is not what you're really asking about.
You are more likely concerned about what happens to the data that was written to the pipe after the child process exits. As the pipe(2) man page states:
Data written to the write end of the pipe is buffered by the kernel
until it is read from the read end of the pipe.
So your data will arrive, even if the process that wrote it has already exited.

C Programming vfork return value

I have to create a program that:
ask for a number
create a child process (using vfork)
calculate the square root (in the child process)
show the square root from the parent process
Here is my code
#include <stdio.h>
#include <sys/types.h>
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
double n=0;
printf("Number: "); //ask number
scanf("%d", &n);
pid_t pid = vfork(); //create child process
if (pid==0)//if child process
{
printf("Child process started\n");
n = sqrt(n);//calculate square root
}
else//parent process
{
printf("Returnning to parent process\n");
printf("Square Root: %d",n);
}
return 0;
}
But my code doesnt work, can anyone help me?
Why would you expect it to work? Doing anything but exec or _exit after vfork results in explicitly undefined behavior. See:
vfork() system call
And some further discussion of the horrors of vfork:
http://ewontfix.com/7/
http://www.openwall.com/lists/musl/2012/12/31/16
In case it's interesting, here is a list of possible problems with your program (manifestations of the UB):
printf in the child could horribly corrupt the parent's stdio state.
n could be stored permanently in a register, in which case there's no way the parent could see the changes made by the child
The compiler can see that n is uninitialized in the else branch, so it need not generate any code to read it at all (this branch unconditionally invoked UB by accessing an object whose value is indeterminate).
You're calculating the square root in the child, but trying to print it in the parent. The parent has no idea what the square root is. If you want the parent to print the square root, then you'll need to communicate that value from the child back to the parent process somehow. It seems more likely that you're supposed to print the square root in the child process.
int main(int argc, char **argv) { int n=0;
pid_t pid = vfork(); //create child process
if (pid==0)//if child process
{
printf("Child process started\n");
scanf("%d",&n);
n = sqrt(n);//calculate square root
_exit(23);
}
else//parent process
{
printf("Returnning to parent process\n");
printf("Square Root: %ld",n);
}
return 0; }

Understanding forks in C

I am having some trouble understanding the following simple C code:
int main(int argc, char *argv[]) {
int n=0;
fork();
n++;
printf("hello: %d\n", n);
}
My current understanding of a fork is that from that line of code on, it will split the rest of the code in 2, that will run in parallel until there is "no more code" to execute.
From that prism, the code after the fork would be:
a)
n++; //sets n = 1
printf("hello: %d\n", n); //prints "hello: 1"
b)
n++; //sets n = 2
printf("hello: %d\n", n); //prints "hello: 2"
What happens, though, is that both print
hello: 1
Why is that?
EDIT: Only now it ocurred to me that contrary to threads, processes don't share the same memory. Is that right? If yes, then that'd be the reason.
After fork() you have two processes, each with its own "n" variable.
fork() starts a new process, sharing no variables/memory locations.
It is very similar to what happens if you execute ./yourprogram twice in a shell, assuming the first thing the program does is forking.
At fork() call's end, both the processes might be referring to the same copy of n. But at n++, each gets its own copy with n=0. At the end of n++; n becomes 1 in both the processes. The printf statement outputs this value.
Actually you spawn a new process of the same progarm. It is not the closure kind of thing. You could use pipes to exchange data between parent and child.
You did indeed answer your own question in your edit.
examine this code and everything should be clearer (see the man pages if you don't know what a certain function does):
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int count = 1;
int main(int argc, char *argv[]) {
// set the "startvalue" to create the random numbers
srand(time(NULL));
int pid;
// as long as count is <= 50
for (count; count<=50; count++) {
// create new proccess if count == 9
if (count==9) {
pid = fork();
// reset start value for generating the random numbers
srand(time(NULL)+pid);
}
if (count<=25) {
// sleep for 300 ms
usleep(3*100000);
} else {
// create a random number between 1 and 5
int r = ( rand() % 5 ) + 1;
// sleep for r ms
usleep(r*100000);
}
if (pid==0) {
printf("Child: count:%d pid:%d\n", count, pid);
} else if (pid>0) {
printf("Father: count:%d pid:%d\n", count, pid);
}
}
return 0;
}
happy coding ;-)
The system call forks more than the execution thread: also forked is the data space. You have two n variables at that point.
There are a few interesting things that follow from all this:
A program that fork()s must consider unwritten output buffers. They can be flushed before the fork, or cleared after the fork, or the program can _exit() instead of exit() to at least avoid automatic buffer flushing on exit.
Fork is often implemented with copy-on-write in order to avoid unnecessarily duplicating a large data memory that won't be used in the child.
Finally, an alternate call vfork() has been revived in most current Unix versions, after vanishing for a period of time following its introduction i 4.0BSD. Vfork() does not pretend to duplicate the data space, and so the implementation can be even faster than a copy-on-write fork(). (Its implementation in Linux may be due less to speed reasons than because a few programs actually depend on the vfork() semantics.)

Resources