How many processes will be created - c

I have this piece of code and was wondering how many processes will be created. I am uncertain as I think because of the loop it will be 12 processes but also could be 8.
#include <unistd.h>
#include <sys/types.h>
int main() {
pid_t childpid;
int i;
childpid = fork();
for (i = 0; i < 3 && childpid == 0; i++) {
if (childpid == -1) {
perror("Failed to fork.");
return 1;
}
fprintf(stderr, "A\n");
childpid = fork();
if (childpid == 0) {
fprintf(stderr, "B\n");
childpid = fork();
fprintf(stderr, "C\n");
}
}
return 0;
}

Yes, you can use aptitude to evaluate how many processes are created, but I let the program decide it for me.
The child and parent are synchronized using semaphore, and a pcount variable is used to keep track of the number of created processes. pcount is incremented whenever childpid is evaluated to zero. Below are the additions to your program.
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
int main(void)
{
/* Initialize and setup a semaphore */
sem_t* sema = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (sema == MAP_FAILED)
exit(1);
if (sem_init(sema, 1, 1) != 0)
exit(1);
/* Initialize pcount */
int* pcount = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (pcount == MAP_FAILED)
exit(1);
*pcount = 1;
printf("pcount = %d\n", *pcount);
pid_t childpid;
int i;
childpid = fork();
if (childpid == 0) {
sem_wait(sema);
*pcount = *pcount + 1;
printf("pcount = %d\n", *pcount);
sem_post(sema);
}
for (i = 0; i < 3 && childpid == 0; i++) {
if (childpid == -1) {
perror("Failed to fork.");
return 1;
}
fprintf(stderr, "A\n");
childpid = fork();
if (childpid == 0) {
sem_wait(sema);
*pcount = *pcount + 1;
printf("pcount = %d\n", *pcount);
sem_post(sema);
fprintf(stderr, "B\n");
childpid = fork();
if (childpid == 0) {
sem_wait(sema);
*pcount = *pcount + 1;
printf("pcount = %d\n", *pcount);
sem_post(sema);
}
fprintf(stderr, "C\n");
}
}
return 0;
}
Terminal Session:
$ gcc SO.c -lpthread
$ ./a.out
pcount = 1
pcount = 2
A
pcount = 3
B
C
pcount = 4
C
A
pcount = 5
B
C
pcount = 6
C
A
pcount = 7
B
C
pcount = 8
C
So yes, 8 is the answer. Easy-Peasy :)

8 processes will be created.
Here is how it looks like after the first loop:

Related

global semaphores for synchronisation - counter

Below i increment a counter 1000 in two different processes and use a global semaphores for synchronisation. But iCounter doesn't give me 2000? Could someone explain to me why?
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <fcntl.h>
#define SEM_NAME "/sync"
#define NUMBER_OF_PROCESSES 2
int main ()
{
int iCounter = 0;
pid_t pid[NUMBER_OF_PROCESSES];
sem_t *sSem = sem_open (SEM_NAME,O_CREAT | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 1);
int i, iStatus;
for (i = 0; i < NUMBER_OF_PROCESSES; i++)
{
pid[i] = fork ();
if (pid[i] < 0)
{
printf ("Could not create process\n");
exit (1);
}
else if (pid[i] == 0)
{
int i;
for (i = 0; i < 1000; i++)
{
sem_init(sSem, 0, 1);
sem_wait (sSem);
iCounter++;
sem_post (sSem);
}
exit (0);
}
}
for (i = 0; i < NUMBER_OF_PROCESSES; i++)
waitpid (pid[i], &iStatus, WUNTRACED);
printf ("Value of iCounter = %d\n", iCounter);
sem_close (sSem);
sem_unlink (SEM_NAME);
}
You have two big issues:
You're not using named semaphores correctly. sem_init() is only meant to be used on anonymous ones, and only once per semaphore, where you're calling it on an already initialized one many times. That's undefined behavior.
Your iCounter variable isn't shared between the processes you create.
The following reworking of your program allocates it using POSIX shared memory (And has some general cleanup):
#include <errno.h>
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define SEM_NAME "/sync"
#define SHM_NAME "/counter"
#define NUMBER_OF_PROCESSES 2
int main() {
int *iCounter = MAP_FAILED;
pid_t pid[NUMBER_OF_PROCESSES];
int iStatus;
int ret = 0;
int memfd = -1;
sem_t *sSem = sem_open(SEM_NAME, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1);
if (sSem == SEM_FAILED) {
perror("sem_open");
ret = 1;
goto cleanup;
}
memfd = shm_open(SHM_NAME, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (memfd < 0) {
perror("shm_open");
ret = 1;
goto cleanup;
}
if (ftruncate(memfd, sizeof *iCounter) < 0) {
perror("ftruncate");
ret = 1;
goto cleanup;
}
iCounter = mmap(NULL, sizeof *iCounter, PROT_READ | PROT_WRITE, MAP_SHARED,
memfd, 0);
if (iCounter == MAP_FAILED) {
perror("mmap");
ret = 1;
goto cleanup;
}
close(memfd);
*iCounter = 0;
for (int i = 0; i < NUMBER_OF_PROCESSES; i++) {
pid[i] = fork();
if (pid[i] < 0) {
fprintf(stderr, "Could not create process: %s\n", strerror(errno));
ret = 1;
goto cleanup;
} else if (pid[i] == 0) {
for (i = 0; i < 1000; i++) {
sem_wait(sSem);
(*iCounter)++;
sem_post(sSem);
}
sem_close(sSem);
return 0;
}
}
for (int i = 0; i < NUMBER_OF_PROCESSES; i++)
waitpid(pid[i], &iStatus, WUNTRACED);
printf("Value of iCounter = %d\n", *iCounter);
cleanup:
if (sSem != SEM_FAILED) {
sem_close(sSem);
sem_unlink(SEM_NAME);
}
if (memfd >= 0)
shm_unlink(SHM_NAME);
return ret;
}
Example:
$ gcc -g -O -Wall -Wextra example.c -lrt -lpthread
$ ./a.out
Value of iCounter = 2000

shm_open segmentation fault and permission failed

I am new to Linux and i am trying to create a shared memory object which stores the collatz conjecture calculated in child process and prints it in parent process. I have already read the man pages for the commands.
When I create the object it prints permission denied and segmentation fault(core dumped). Only one time it somehow passed that step then I got the mapping failed error.I am using ubuntu 18.04 on a virtual machine
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/wait.h>
#include<sys/stat.h>
int main(int argc,char** argv)
{
pid_t pid;
pid = fork();
int page_size = 4096;
char obj[] = "name";
int num = atoi(argv[1]);
if(num < 1)
{
printf("Please input a greater number\n");
return 0;
}
if(pid < 0)
{
fprintf(stdout,"Fork failed\n");
}
else if(pid == 0)
{
int fd1 = 0;
void *ptr1 = NULL;
fd1 = shm_open(obj,O_CREAT|O_TRUNC,S_IRWXU);
if (fd1 == -1)
{
perror("error:");
exit(0);
}
ftruncate(fd1,page_size);
ptr1 = mmap(0,page_size,PROT_WRITE,MAP_SHARED,fd1,0);
if(ptr1 == MAP_FAILED)
{
fprintf(stdout,"Mapping failed");
exit(0);
}
else
{
while(num != 1)
{
if(num%2 == 0)
num = num / 2;
else
num = (num * 3) + 1;
sprintf(ptr1,"%d, ",num);
}
}
}
else
{
wait(NULL);
int fd = 0;
void *ptr = NULL;
shm_open(obj,O_RDONLY,S_IRWXU);
ptr = mmap(0,page_size,PROT_READ,MAP_SHARED,fd,0);
char *pr = (char *)ptr;
fprintf(stdout,pr);
shm_unlink(obj);
}
return 0;
}
Your code needs a couple of changes, some for better programming practices and some for fixing the actual functionality:
#include <all.h>
int main(int argc, char **argv) {
pid_t pid;
pid = fork();
int page_size = 4096;
char obj[] = "name";
// check argc otherwise you'll segfault
if (argc < 2) {
printf("Please provide a second argument.\n");
// if the program errors it should not return 0
return 1;
}
int num = atoi(argv[1]);
if (num < 1) {
printf("Please input a greater number\n");
return 1;
}
if (pid < 0) {
// no need for fprintf(stdout
printf("Fork failed\n");
} else if (pid == 0) {
int fd1 = 0;
char *ptr1 = NULL;
// we need to open with O_RDWR otherwise mmap will fail
fd1 = shm_open(obj, O_CREAT | O_TRUNC | O_RDWR, 0666);
if (fd1 == -1) {
perror("shm_open error");
return 1;
}
ftruncate(fd1, page_size);
// cast it to char* directly, no need for void pointer stuff
ptr1 = (char *) mmap(0, page_size, PROT_WRITE, MAP_SHARED, fd1, 0);
if (ptr1 == MAP_FAILED) {
// perror for debugging
perror("mmap error");
printf("Mapping failed.\n");
return 1;
} else {
while (num != 1) {
if (num % 2 == 0)
num = num / 2;
else
num = (num * 3) + 1;
// we need to shift the pointer so it stops truncating
ptr1 += sprintf(ptr1, "%d, ", num);
}
}
} else {
wait(NULL);
// move these to one like and cast to char* directly
int fd = shm_open(obj, O_RDONLY, S_IRWXU);
char *ptr = (char*) mmap(0, page_size, PROT_READ, MAP_SHARED, fd, 0);
// no need for fprintf(stdout, and also use %s\n as a format to add a newline
printf("%s\n", ptr);
shm_unlink(obj);
}
return 0;
}

Shared memory with forked child

I have the following code which is supposed to create a forked process to execute the Collatz conjecture (based on a passed value), and push the integers into shared memory. When the child process is done, the parent process is supposed to print out the values. For some reason, my code works sometimes but not others. From debug statements, I can see the values get pushed in but sometimes the code to print out the values doesn't appear to execute (just some blank lines get printed). I am using Debian Linux in a virtual box.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 2048;
const char *name = "SHARON";
int shm_fd;
void *ptr;
int count = 1;
/* Setup shared memory */
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, SIZE);
ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
/* Get the starting value */
int value;
printf("Enter a positive integer value: ");
scanf("%d", &value);
printf("\n");
if (value < 0)
{
printf("ERROR: Integer value must be positive!");
return 1;
}
/* Fork child process */
pid_t pid;
pid = fork();
fork();
if (pid < 0)
{
fprintf(stderr, "FORK FAILED\n");
return 1;
}
else if (pid > 0) /*parent process*/
{
wait(); /*wait for child to send */
while (atoi((char *)ptr) != 0) /*0 is terminate value*/
{
printf("%s", (char *)ptr);
ptr += sizeof(int);
if (atoi((char *)ptr) != 0)
printf(", ");
}
printf("\n");
shm_unlink(name);
}
else if (pid == 0) /* child process */
{
sprintf(ptr, "%d", value);
ptr += sizeof(value);
while (value != 1)
{
if (value % 2 == 0)
value /= 2;
else
value = value * 3 + 1;
sprintf(ptr, "%d", value);
ptr += sizeof(value);
}
sprintf(ptr,"0"); //push a "terminate" value
ptr += sizeof(value);
}
return 0;
}
Any hints on what I'm doing wrong?
There is two fork() call. which will create two child.
pid = fork();
//fork();
Can you try with above.

C fork distinguish between father and sons

My problem is the stock doesnt change i think there is something wrong in the if statement pid[i] == 0. I doenst get the prints from the "father process part" of my code only from the childs.
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/types.h>
#define NUM_CHILDS 3
#define LOOPS 6
#define FILLING_UP 20
#define SHMSEGSIZE sizeof(int)
int main() {
int shmID1, shmID2, *stock, *flag, loop_i, pid[NUM_CHILDS], i;
loop_i = 1;
shmID1 = shmget(IPC_PRIVATE, SHMSEGSIZE, IPC_CREAT | 0644);
shmID2 = shmget(IPC_PRIVATE, SHMSEGSIZE, IPC_CREAT | 0644);
stock = (int *) shmat(shmID1, 0, 0);
flag = (int *) shmat(shmID2, 0, 0);
*stock = 20;
*flag = 1;
for (i = 0; i < NUM_CHILDS; i++) {
pid[i] = fork();
if(pid[i] == -1) {
printf("error by crating a child!\n\n");
return -1;
}
if (pid[i] == 0) {
printf("Child %d: %d", i, pid[i]);
while(*flag==1) {
if(*stock>0) {
*stock--;
usleep(100000);
}
}
shmdt(flag);
shmdt(stock);
return 0;
}
else {
while(loop_i <= LOOPS) {
usleep(100000);
printf("Actual stock: %d\n", *stock);
if(*stock<=0) {
*stock += FILLING_UP;
loop_i++;
printf("Stock is filled up");
}
}
*flag = 0;
}
}
for (i = 0; i < NUM_CHILDS; i++) {
waitpid(pid[i], NULL, 0);
}
printf("Programm ends", LOOPS, *stock);
shmdt(flag);
shmdt(stock);
shmctl(shmID1, IPC_RMID, 0);
shmctl(shmID2, IPC_RMID, 0);
return 0;
}
The fork() in Linux is used to create new process. Also after forking, it returns 0 in child process and returns pid of child process in parent process. So in parent process pid!=0. Hence the statement inside the if(pid==0) will not execute in parent process.
You should reset loop_i to 1. Otherwise the while loop in the parent will run LOOPS times for the first child and 0 times for the other children.
loop_i = 1;
while(loop_i <= LOOPS) {
...
}

Forking 3 processes, using shared memory

I have an assignment, and im beating my head against the wall. It is in C. I have a feeling im close to the solution, however I cant get the program to do whats required. I am changing the numbers and some small details, because most of the class is as stumped as I.
Requirements: Create 3 processes, the first one will increment a shared memory variable "total->value" from 1 to 10000, the second from 10000 to 12000, the third from 12000 to 14000
The process functions are labeled such (process1(), process2(), process3())
and the internals of those functions are as follows
process1()
{
int k = 0;
while (k < 10000)
{
k++;
total->value = total->value + 1;
}
printf("From process 1 = %d/n", total->value);
}
The second would be k < 2000 (because it only needs to increment the shared value 2000 more) and etc.
The main portion of the program is:
main()
{
int shmid;
int pid1;
int pid2;
int pid3;
int ID;
int status;
char *shmadd = (char *)0;
/* Create and connect to a shared memory segmentt */
if ((shmid = shmget(SHMKEY, sizeof (int), IPC_CREAT | 0666)) < 0)
{
perror("shmget");
exit(1);
}
if ((total = (shared_mem *)shmat(shmid, shmadd, 0)) == (shared_mem *)-1)
{
perror("shmat");
exit(0);
}
total->value = 0;
if ((pid1 = fork()) == 0)
process1();
if ((pid1 != 0) && (pid2 = fork()) == 0)
process2();
if ((pid1 != 0) && (pid2 != 0) && (pid3 = fork()) == 0)
process3();
if ((pid1 != 0) && (pid2 != 0) && (pid3 != 0))
{
if ((shmctl(shmid, IPC_RMID, (struct shmid_ds *)0)) == -1)
{
perror("shmctl");
exit(-1);
}
printf("\t\t End of Program.\n");
}
}
What I need is for the first process to finish, before the 2nd starts. I tried inserting a wait(&status) after the process1() (or 2 or 3) calls and am at a loss. Any pointers? (no pun intended) =) there is more to implement, but I believe once I have this part I can handle the rest on my own. I have been intentionally vague in some regards, but I would like to finish this project and more importantly understand it and there are others who want a free lunch. I will provide anything else in the code that is required. Thank you in advance for your help
The output should appear
From process 1 = 10000
From process 2 = 12000
From process 3 = 14000
I believe that Celada's comment/guess on the requirements is correct. However, barring that, and at the risk of doing too much work, the following code fulfills your spec. The use of the gcc built-in __sync_fetch_and_add() is perhaps unnecessary.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>
static struct {
int value;
} *total;
static void process1(void) {
int k = 0;
while (k < 10000) {
k++;
__sync_fetch_and_add(&total->value, 1);
}
printf("From process 1 = %d\n", total->value); //<-- not quite right: could be >10000
}
static void process2(void) {
int k = 0;
while (__sync_fetch_and_add(&total->value, 0) != 10000)
;
while (k < 2000) {
k++;
__sync_fetch_and_add(&total->value, 1);
}
printf("From process 2 = %d\n", total->value);
}
static void process3(void) {
int k = 0;
while (__sync_fetch_and_add(&total->value, 0) != 12000)
;
while (k < 2000) {
k++;
__sync_fetch_and_add(&total->value, 1);
}
printf("From process 3 = %d\n", total->value);
}
int main(void) {
int shmid;
int pid1;
int pid2;
int pid3;
int status;
/* Create and connect to a shared memory segment */
if ((shmid = shmget(1234, sizeof *total, IPC_CREAT|0666)) < 0) {
perror ("shmget");
exit (1);
}
if ((total = shmat(shmid, 0, 0)) == (void *)-1) {
perror("shmat");
exit (0);
}
total->value = 0; // not necessary in Linux if IPC_CREAT invoked
if (!(pid1 = fork()))
process1();
else if (!(pid2 = fork()))
process2();
else if (!(pid3 = fork()))
process3();
else {
wait(&status);
wait(&status);
wait(&status);
if ((shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0)) == -1) {
perror("shmctl");
exit (-1);
}
printf("\t\t End of Program.\n");
}
return 0;
}

Resources