How to shared memory with parent and child processes in c - 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).

Related

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

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!

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.

Processes and semaphores

So i was experimenting on how to use fork and semaphores for a homework and it seems everytime i run the program fork always returns a number >0, while what i wanted was to first have several processes be made then be stopped using semaphores and then have some of them restart again.
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
int main(int argc,char *argv[])
{
int i,count;
count = 0;
pid_t *Pc;
Pc=(pid_t *) malloc((argc-2)*sizeof(pid_t));
sem_t *sem;
sem = (sem_t *) malloc((argc-2)*sizeof(sem_t));
for (i = 0; i <= argc-2; i++){
sem_init(&sem[i], 0, 0);
}
for (i =0; i<=argc-2; i++){
Pc[i] = fork();
if (Pc[i] == 0){
printf(" child");
sem_wait(&sem[i]);
printf("Experiment was a success!");
}
if (Pc[i]>0){
printf("Parent");
}
}
for (i =0; i<=argc-2; i++){
if (Pc[i] > 0)
count++;
}
for (i= 0; i<=3; i++){
if ( count == argc-2){
sem_post(&sem[i]);
}
}
}
nameofprogram 1 2
prints: Parent
Child
Parent
Child
You need to read the man page for sem_init(). The type of semaphore you are creating right now is not shared across processes. This requires a non-trivial change to your program, because you also need to set up shared memory. Refer to this question for a lengthy explanation of how to make your program work.
When a program calls fork, a new process is created with a new exact copy of the memory space. This mean that sem in your child process is not the same as sem in your parent process. So, when you call sem_post, you child process can not be notified of the change and get out of the wait function.
To solve this, you have different possibilities:
Create a shared memory which can be read by all your processes and create this semaphore in this shared memory, as already suggested.
Use named semaphores with sem_open. This kind of semaphore can be shared across different processes as it work like a file handle. This seems to be an easier way if you only need a shared semaphore (example here). You will have to generate a unique name for each semaphore in your array (may be only one semaphore on which you call sem_post multiple times would be enough for your use).
Keep your semaphores and use threads instead of processes (but I guess your homework is about processes so this may not be an option for you)

How and why can fork() fail?

I'm currently studying the fork() function in C. I understand what it does (I think). Why do we check it in the following program?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int pid;
pid=fork();
if(pid<0) /* Why is this here? */
{
fprintf(stderr, "Fork failed");
exit(-1);
}
else if (pid == 0)
{
printf("Printed from the child process\n");
}
else
{
printf("Printed from the parent process\n");
wait(pid);
}
}
In this program we check if the PID returned is < 0, which would indicate a failure. Why can fork() fail?
From the man page:
Fork() will fail and no child process will be created if:
[EAGAIN] The system-imposed limit on the total number of pro-
cesses under execution would be exceeded. This limit
is configuration-dependent.
[EAGAIN] The system-imposed limit MAXUPRC (<sys/param.h>) on the
total number of processes under execution by a single
user would be exceeded.
[ENOMEM] There is insufficient swap space for the new process.
(This is from the OS X man page, but the reasons on other systems are similar.)
fork can fail because you live in the real world, not some infinitely-recursive mathematical fantasy-land, and thus resources are finite. In particular, sizeof(pid_t) is finite, and this puts a hard upper bound of 256^sizeof(pid_t) on the number of times fork could possibly succeed (without any of the processes terminating). Aside from that, you also have other resources to worry about like memory.
There is not enough memory available to make the new process perhaps.
If the kernel fails to allocate memory for example, that's pretty bad and would cause fork() to fail.
Have a look at the error codes here:
http://linux.die.net/man/2/fork
Apparently it can fail (not really fail but hang infinitely) due to the following things coming together:
trying to profile some code
many threads
much memory allocation
See also:
clone() syscall infinitely restarts because of SIGPROF signals #97
Hanging in ARCH_FORK with CPUPROFILE #704
SIGPROF keeps a large task from ever completing a fork(). Bug 645528
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
size_t sz = 32*(size_t)(1024*1024*1024);
char *p = (char*)malloc(sz);
memset(p, 0, sz);
fork();
return 0;
}
Build:
gcc -pg tmp.c
Run:
./a.out

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