Why is the following statements printing thrice? - c

Here is my program:
int main(int argc, char * argv[])
{
pid_t child;
int i=0;
if( argc < 4 ){
printf("Usage: %s <num_threads> <test_interval> <no_of_prints>\n", argv[0]);
exit(1);
}
// Some program logic goes here
printf("context - switch \n\nPid\ttid\tNPid\tNtid\tJiffies\n\n");
syscall(320);
child = fork();
if(child == 0 ) { //in child
fork();
fork();
process();
}
else {
wait(child);
//Do some printing here
}
My output has 3 (and sometimes 2) prints of "context - switch" printf line.

It's probably because of stdio buffering. In a nutshell, multiple processes (the parent, it children, grandchildren etc) end up with the same buffer and they all write it to the screen when they die. Try:
printf("context - switch \n\nPid\ttid\tNPid\tNtid\tJiffies\n\n");
fflush(stdout);
Or maybe just use write(2) instead of printf.

Related

Two way communication from the file that run with exec in child

I am creating a child process with a fork in program y. In that child, I run another program with exec, in which I want the function in that program (let's call it program x) to return something to me. Is there a way to pass this returned value to the parent?
I provided some sort of a pseudo-code that demonstrates what I want to do below.
program.x:
int main(int argc, char** argv)
{
if(argc != 2)
{
printf("argument count does not match\n");
return -1;
}
printf("task1!\n");
...
char *value = "want this"; // how to pass this to the parent in the program y?
...
}
program y:
int main(int argc, char *argv[])
{
int fd[2];
pipe(fd);
pid_t p;
p = fork();
if(p==-1)
{
printf("There is an error while calling fork()");
}
if(p==0)
{
printf("We are in the child process\n");
printf("Calling hello.c from child process\n");
char *args[] = {"Hello", "C", "Programming", NULL};
execv("./hello", args);
close(fd[0]);
write(fd[1], ???, ??);
close(fd[0]);
}
else
{
printf("We are in the parent process");
wait(NULL);
close(fd[1]);
read(fd[0], ???,???);
close(fd[0]);
}
return 0;
}
The only thing you can pass directly is the exit code of the child (via wait()).
To pass a string between two processes, you need an IPC data structure like pipes. See the pipe() function in unistd.h.
For the simple case where there is one-way communication from a child to a parent), you can use popen. It's high level, simple to use, and has little overhead (if any) over fork/exec
int main(...)
{
...
FILE *fp = popen("./hello 'Hello', 'C', 'Programming'", "r") ;
char resp[200] ;
if ( fgets(resp, sizeof(resp, fp) ) {
// Do something
}
int result = pclose(fp) ;
}
Note that the way to pass command line arguments follows shell rules - arguments may need to be quoted (usually, single quote) to pass any special characters.
The 'pclose' result is the exit code of the executed program.

Does anyone see any mistakes here? I am trying to get a message via a pipe, from my parent to child

The problem here is that the child process does not wait for the message to arrive from the function startWorking(), and because of that I am getting a random char as output or sometimes nothing.
I am sending a char array from startWorking() to the pipe and I am making sure only the parent does this job.
One solution would be, sending a signal from startWorking() to the child processor, after writing into the pipe.
But the read() function behavior is waiting for the pipe to receive the message and only then read the message, but somehow it's not doing that, or maybe there is a problem in writing the message.
int main(int argc, char const *argv[])
{
pid_t pid;
pid = fork();
int mypipefd[2];
if (pid > 0)
{
if (pipe(mypipefd) == -1)
{
perror("Pipe failed\n");
exit(EXIT_FAILURE);
}
storeEngine(mypipefd);
}
else if(pid < 0)
{
perror("fork call failed \n");
exit(EXIT_FAILURE);
}
else
{
printf("I am the child \n");
printf("child: %d \n", getpid());
char message[6];
close(mypipefd[1]);
read(mypipefd[0], &message, 6);
close(mypipefd[0]);
printf("child read value:\n ");
printf("%s \n", message);
}
return 0;
}
void startWorking(int *mypipefd)
{
printf("%d \n" ,getpid());
//close(*mypipefd);
write(*(mypipefd+1), "hello", 6);
close(*(mypipefd+1));
}
Notice that if I remove the two slash behind close(*mypipefd) the program will never finish, and it will get stuck there.
Without examining the rest of your code, you need to call pipe() before you call fork() so the pipe can be used by both the parent and the child process. If you call pipe() after you call fork(), the pipe is only usable by that one process.
More like this:
int main(int argc, char const *argv[])
{
int mypipefd[2];
if ( pipe( mypipefd ) == -1 )
{
perror("Pipe failed\n");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid > 0)
{
storeEngine(mypipefd);
}
.
.
.
No, pipes used to communicate between processes should be created before the fork() (otherwise, you have no easy way to send thru them, since the reading and the writing ends should be used by different processes).

execvp in C not going through ar

I'm trying to use exec to execute a list of commands given as arguments.
Example input when In run the program would be ./assn2 ls date.
When I do this only the first command is executed.
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main(int argc, char *argv[])
{
int args = argc-1;
pid_t childpid = fork();
// error
if (childpid < 0)
{
perror("fork() error");
exit(-1);
}
// parent process
if (childpid != 0)
{
printf("Parent Process started, now waiting for ID: %d\n", childpid);
wait(NULL);
printf("Parent Process resumeed. Child exit code 0. Now terminating\n");
exit(0);
}
// child process
if (args > 0)
{
printf("Child process has begun. %d argument/s provided\n", args);
int i;
for (i = 1; i <= argc; i++)
{
execlp(argv[i], argv[i], NULL);
}
execvp(argv[1], argv);
}
else
{
printf("No arguments provided, terminating child\n");
}
return 0;
}
Once the first child process execs (and succeeds), the for loop no longer continues because the an execlp would just replace the current process image with the command being exec'ed.
What you want to do is to loop over the command line arguments in the parent process and exec once for each of the command. Something like is probably what you're after:
for(int i = 1; i < argc; i++) {
pid_t pid = fork();
if (pid == 0) {
execlp(argv[i] ,argv[i], (char*)0);
perror("exec");
} else if (pid > 0) {
wait(NULL);
} else {
perror("fork");
exit(1);
}
}
What are you trying to achieve with the sequential calls to execlp() and execvp()? These functions are not meant to return. I think you should read the ref:
The exec() family of functions replaces the current process image with a new process image. [..] The exec() functions only return if an error has occurred.
As a result you cannot execute them one after another in the same process.
Read about fork():
fork() creates a new process by duplicating the calling process.
Moreover, here:
for(i = 1; i <= argc; i++)
you go out of bounds, since argv starts indexing from 0, and ends at argc - 1.
Chnage it to:
for(i = 1; i < argc; i++)

C - program is terminated (fork() and exec())

I have the following code:
int main(int argc, char **argv)
{
char *program;
char stringa[1000] = "";
int num = 123;
char snum[5];
program = argv[1];
sprintf(stringa, "./%s", program);
pid_t pid = fork();
if (pid < 0 ) {
perror("fork failed.");
exit(1); }
else if (pid == 0) {
char* args[] = {stringa, NULL};
execv(args[0], args);
}
else {
char procmon_str[] = "./procmon ";
num = pid;
sprintf(snum, "%d",num);
printf("PID of child is %s", snum);
char* args2[] = {procmon_str, snum, NULL};
execv(args2[0], args2);
sleep(20);
kill(num, SIGTERM);
sleep(2);
int parent_pid = getpid();
printf("PID of parent is %d", parent_pid);
kill(parent_pid, SIGTERM);
}
wait(NULL);
return 0;
}
The idea is to call with program with 1 command line argument which is a name of another compiled C program in the same folder.
I want to execute that program from within the C code (hence the use of fork()), and at the same time i want to launch another program from within the parent part of the fork().
The part that is in the child part of fork() works perfectly, but when i run it through the shell it says Terminated right after and does not execute the code in the parent part of the fork().
Why is that?
Your program call fork(). Now the execution of the parent process and the child process proceeds in parallel.
The child:
Builds the argument array args[].
Calls execv() and is replaced by the program supplied as argument.
The parent, in parallel with the child:
Builds the argument array args2[].
Calls execv() and is replaced by ./procmon.
The code from sleep(20) onwards in not reached unless the execv() fails (which you did not check for).
Read the manual page for fork() again, and redo the logic of the program.

Multiple child processes with pipe

I wrote a C program that is supposed to create a certain number of child processes, each child process having to change 1 letter from a string. The string and the number of child processes are read from the keyboard.
For example:
input:
3 Apples
output:
Applex Appldx Apqldx
My problem is: Only the parent changes a letter and the children don't.
Unsure what I'm doing wrong. Help would be much appreciated, thanks in advance!
EDIT:
I feel i wasn't clear enough. I want to do it using pipes.
It should work like this: The parent changes one letter, then the first child takes the string modified by the parent and changes one more letter.
The second child takes the string modified by the first one (2 letters are already changed) and changes one more and so on. I am new to C and am not quite sure how it all works, especially pipes.
Also can the children be linked between them through the pipe, or can the only linked to the parent and it has to be something like: first child changes a letter, gives the string back to the parent and then the second child reads from there, modifies letter and gives back.
If it's like that, is there any way to make sure that this doesn't happen: Apples becomes AppleD and then AppleX and then AppleQ?
Here's my code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include <sys/wait.h>
void error(char* msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
static void modify(char msg[]) {
srand(time(NULL));
int pos1=rand()%((int)strlen(msg));
srand(time(NULL));
int pos2=rand()%26;
srand(time(NULL));
int big=rand()%2;
if(big==1) {
msg[pos1]=(char)(((int)'A')+pos2);
}
else {
msg[pos1]=(char)(((int)'a')+pos2);
}
return;
}
int main(int argc, char *argv[])
{
if(argc!=3) {
error("Wrong number of arguments\n");
}
int nrch;
nrch=atoi(argv[1]);
char* msg=argv[2];
printf("Parent: erhalten: %s\n", msg);
int i=0;
modify(argv[2]);
printf("Parent: weiter: %s\n", msg);
srand(time(NULL));
pid_t pids[10];
int fd[2];
/* Start children. */
for (i = 0; i < nrch; ++i) {
if (pipe(fd) == -1) {
error("Can’t create the pipe");
}
if ((pids[i] = fork()) < 0) {
error("Can't fork process");
}
else if (pids[i] == 0) {
//dup2(fd[1], 1);
//close(fd[0]);
printf("child%d: erhalten: %s\n", (i+1), msg);
modify(msg);
printf("child%d: weiter: %s\n", (i+1), msg);
exit(0);
}
}
/* Wait for children to exit. */
int status;
pid_t pid;
while (nrch > 0) {
pid = wait(&status);
printf("Child with PID %ld exited with status 0x%x.\n", (long)pid, status);
--nrch;
}
}

Resources