I want to create multiple processes from one master process. I know I want to use a function from the exec family, but it does not seem to be preforming in the way I intended it to. It seems that exec() is a blocking call, or maybe I am just using it wrong. Anyway, on to the code:
const char* ROUTERLOCATION = "../../router";
int main(int argc, char** argv) {
manager manager;
vector<string> instructions = manager.readFile(argv[1]);
...
//file gives me the number of proceses i want to spawn and that value goes in
//rCount
for(int i = 0; i < rCount; i++){
cout << "creating:" << i << endl;
execl(ROUTERLOCATION, "",NULL);
}
}
The output I see is:
creating:0
HI!!!
And then everything exits gracefully. Can I not spawn more than one process using execl()?
Also, I would like to communicate with each of these processes, so I don't want to be blocking while these processes are running.
You need to fork in your master process, the in your child processes call execl. (exec family of functions replaces your current process image with your new process, so hence why your for loop never completes.)
calling exec() means that your current program not longer exists. You might want to create a new process using fork() and then call exec() in it so that exec() replaces your new process and your main process still works as you intend it to.
example:
pid_t pid = fork();
if (pid == 0) {// child
execl();
} else { // parent
}
Related
#1 code
int child_pid;
for (int i = 0; i < 3; i++)
{
child_pid = fork();
if (child_pid == 0)
{ sleep(10); }
else
{ wait(&status); }
}
execlp("sleep","sleep","20",(char*)NULL);
#2 code
int child_pid;
for (int i = 0; i < 5; i++)
{
child_pid = fork();
if (child_pid == 0)
{ sleep(1); }
else
{ wait(&status);
execlp("sleep","sleep","20",(char*)NULL); }
}
Can someone explain to me what is happening in these codes?
I understand fork() returns a zero to a newly created child process. That's why I don't understand why in #2 code the else branch is also being executed? Execlp replaces the calling process image with a new process image, but what does this really mean?
EDIT:
The answer is that the first code will create 8 processes, but I'm not able to understand how? And why will the first code finish 230 seconds? How does exec affect this?
The second code will create 5 processes, but it will finish after (5*2sec+5*20sec). In the second code why does it go to the else branch?
I'm trying to understand how many processes are created as well as why and how long the code will sleep?
Thanks in advance.
fork will return two times, one in the original process, with the return value of the pid of the child process, the other in the child process, with the return value of zero
DESCRIPTION
fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process.
and:
RETURN VALUE
On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
So, after to fork(), you have your newly created process, so you have 2 process, the child (the new process) and the parent (the initial process).
So, what your child (pid == 0) is going into the sleep when you parent (pid > 0) is executing your sleep.
After doing an exec* (execl, execlp, execv, execve, etc...) your process is terminated (try to place a printf or whatever AFTER your execlp, you will see it will never print it (except in case of error (execlp's return value == -1)).
To answer to your initial question:
Yes, your program pass in your if AND in your else (put printf to see clearer), because you have in fact 2 process, and you can even try to put a printf after the else statement, at the very end of your program, and you will see that the child pass (print his pid, it should be equal to 0).
This is my sender thread once after it is called for first time its finish its execution. I Couldn't be able to resume this sender thread. Is There any mechanism in C++ to resume threads.
void ClientSocket::sender()
{
char buf[1024];
//readBuffer = m_ptrsendStream->Read_Adt(filePath);
//readStream();
//cout << readBuffer.str()<<endl;
cout << "write stream to send through socket\n" << endl;
cin >> buf;
if (isConnected == 0)
{
//send(clientSock, readBuffer.str().c_str(), strlen((char *)readBuffer.str().c_str()), 0);
send(clientSock, buf, strlen(buf), 0);
cout << "sending stream :\n"<<endl << buf << endl;
}
}
//this is where my thread creation happens and join() happens.
int main(int argc, char *argv[])
{
ClientSocket objSocket(argv[1]);
sender_thread = make_shared<thread>([&objSocket]() {
objSocket.sender();
});
try
{
if (sender_thread->joinable())
sender_thread->join();
}
No, once your thread has joined it's done and you need to create a new one.
If you have this pattern where you are constantly creating new threads it might be worthwhile to think about using a threadpool to avoid the overhead of constantly spawning new threads.
In addition, if this is related to networking it's probably best to avoid using threads and instead use something asynchronous like boost::asio.
Terminated threads cannot be resumed (this is not a C++ limitation, but a general limitation; when speaking about resuming thread, it is usually about resuming after previously suspending it).
After join() has returned, corresponding thread is already terminated; it has no state (except maybe for zobmie stuff and return code, but this is of no use for your purposes), and there is nothing to resume
However, it is possible to run your sender() function in another thread, just create another instance of your thread.
EDIT: I concur with #inf on using asio instead of threads whenever possible.
You want resume thread which is completed , normally thread resume used continue from suspended threads . Instead of resuming the thread ,stop come of thread un till it finish all actions , make use of while or wait in thread .
What the code actually does is takes input from parent process, sends it to child process through pipe. Child process reverses it then sends it back to parent through another pipe. There is no waitpid() or wait() function in the code.
The question is: How the process switching is working here? How write() and read() functions are working here?
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <iostream>
#define li long int
using namespace std;
void ReverseAString(char input[])
{
li length = strlen(input),i;
char hold;
for(i=0;i<length/2;i++)
{
hold = input[i];
input[i] = input[length-(i+1)];
input[length-(i+1)] = hold;
}
}
int main()
{
pid_t ChildOrParentId;
int fifoParent[2],fifoChild[2],in;
if(pipe(fifoParent)==-1)
{
cout<<"Problem in creating Parent's Pipe"<<endl;
perror("Parent's Pipe");
exit(1);
}
if(pipe(fifoChild)==-1)
{
cout<<"Problem in creating Child's Pipe"<<endl;
perror("Child's Pipe");
exit(1);
}
ChildOrParentId = fork();
if(ChildOrParentId==0)
{
char buf[100],collected[100];
close(fifoParent[0]);
close(fifoChild[1]);
in = 0;
while(read(fifoChild[0],buf,1)>0)
{
collected[in]=buf[0];
in++;
}
collected[in]=0;
cout<<"Read from Child "<<collected<<endl;
ReverseAString(collected);
cout<<"After Reversing: "<<collected<<endl;
write(fifoParent[1],collected,sizeof(collected));
close(fifoParent[1]);
}
else
{
char buf[100],collected[100];
close(fifoParent[1]);
close(fifoChild[0]);
in = 0;
cout<<"Enter a string: ";
gets(buf);
write(fifoChild[1],buf,sizeof(buf));
close(fifoChild[1]);
while(read(fifoParent[0],buf,1)>0)
{
collected[in] = buf[0];
in++;
}
collected[in] = 0;
cout<<"Read from Parent "<<collected<<endl;
}
return 0;
}
Output window looks like this:
Enter a string: abc // abc input given
Read from child abc
After reversing: cba
Read from parent cba
Normally, read on an empty pipe blocks until data is made available by writing to the write end of the pipe.
Thus, the child process can't continue execution past this line until it receives data from the parent; it blocks waiting for it:
while(read(fifoChild[0],buf,1)>0)
Once it has read the string, it wakes up, reverses it, and writes it back to the parent. The parent might also be blocked when it reaches the following line, waiting for the child process to write the reversed string:
while(read(fifoParent[0],buf,1)>0)
The blocking behaviour of read is similar to the blocking behaviour of wait or waitpid, but it waits for data to arrive on the file descriptor, rather than waiting for a child process to change status.
In general, parent and child processes execute simultaneously, except when one or both are blocked on a system call.
The moment you call fork(), a second process is created, and both processes are at this point in the code. The only way to tell if you're the new child process or the original parent process is to look at the return value of fork(). In the documentation, you can see that if fork() returns 0, you are in the child process. So basically, the then block of the if(ChildOrParentId==0) statement only runs in the child process, and the else block only runs in the parent process.
The rest of the explanation is pretty straight forward if you look at those two blocks as different programs. The parent block asks for a string, sends it to the child, waits for the child to send something back, then prints what the child sent. Meanwhile, the child block waits for something from the parent, prints what it gets, reverses it and prints that, then sends the reversed string back to the parent.
using linux commands in my c++ program. Trying to download a url from a list of arrays, once one download finishes, the next to start.... currently only downloads the first location in the array, then stops.
Does somebody see the error i'm doing?
// Begin the downloading process
pid_t child = 0;
child = fork();
if ( child < 0)
{
cout << "Process Faileld to Fork<<endl;
return 1;
}
if (child == 0)
{
wait(NULL);
}
else
{
for(int i = 0; i < numberOfDownloads; i++)
{
execl("/usr/bin/wget", "wget",locations[i], NULL);
}
}
trying to download something with the command wget, but i get an error
execl replaces the currently running process by the started process. So your loop body is only run once. You should put the fork() inside the loop, assuming you want to fork off numberOfDownloads instances of wget. (but be careful with such things)
Otherwise, use system(), which will not terminate your process but return to your loop after wget exits. Or popen(), if you need more control over the process and want to read wget output, without having to do all the I/O heavylifting yourself.
I am kind of newbie on C++, and working on a simple program on Linux which is supposed to invoke another program in the same directory and get the output of the invoked program without showing output of the invoked program on console. This is the code snippet that I am working on:
pid_t pid;
cout<<"General sentance:"<<endl<<sentence<<endl;
cout<<"==============================="<<endl;
//int i=system("./Satzoo");
if(pid=fork()<0)
cout<<"Process could not be created..."<<endl;
else
{
cout<<pid<<endl;
execv("./Satzoo",NULL);
}
cout<<"General sentance:"<<endl<<sentence<<endl;
cout<<"==============================="<<endl;
One of the problem I encounter is that I am able to print the first two lines on console but I cant print the last two lines. I think the program stops working when I invoke the Satzoo program.
Another thing is that this code invokes Satzoo program twice, I dont know why? I can see the output on screen twice. On the other hand if I use system() instead of execv(), then the Satzoo works only once.
I haven't figured out how to read the output of Satzoo in my program.
Any help is appreciated.
Thanks
You aren't distinguisng between the child and the parent process after the call to fork(). So both the child and the parent run execv() and thus their respective process images are replaced.
You want something more like:
pid_t pid;
printf("before fork\n");
if((pid = fork()) < 0)
{
printf("an error occurred while forking\n");
}
else if(pid == 0)
{
/* this is the child */
printf("the child's pid is: %d\n", getpid());
execv("./Satzoo",NULL);
printf("if this line is printed then execv failed\n");
}
else
{
/* this is the parent */
printf("parent continues execution\n");
}
The fork() function clones the current process and returns different values in each process. In the "parent" process, it returns the pid of the child. In the child process, it returns zero. So you would normally invoke it using a model like this:
if (fork() > 0) {
cout << "in parent" << endl;
} else {
cout << "in child" << endl;
exit(0);
}
I have omitted error handling in the above.
In your example, both of the above code paths (both parent and child) fall into the else clause of your call to fork(), causing both of them to execv("./Satzoo"). That is why your program runs twice, and why you never reach the statements beyond that.
Instead of using fork() and doing everything manually (properly managing process execution is a fair amount of work), you may be interested in using the popen() function instead:
FILE *in = popen("./Satzoo", "r");
// use "in" like a normal stdio FILE to read the output of Satzoo
pclose(in);
From the fork() manpage:
RETURN VALUE
Upon successful completion, fork() shall return 0 to the child process and shall return the process ID of the child process to the parent process. Both processes shall continue to execute from the fork() function. Otherwise, -1 shall be returned to the parent process, no child process shall be created, and errno shall be set to indicate the error.
You check to make sure it succeeds, but not whether the pid indicates we're in the child or the parent. Thus, both the child and the parent do the same thing twice, which means that your program gets executed twice and the ending text is never printed. You need to check the return value of fork() more than just once.
exec - The exec() family of functions replaces the current process image with a new process image.
system - Blocks on execution of the command. Execution of the calling program continues after the system command returns
There are three return value tests you want with fork
0: you are the child
-1: error
other: you are the parent
You ran the other program from both the child and the parent...