Ok so I have been trying to learn to master child processes and properly waiting for them to finish. I have read a lot of Stack Overflow Q/A and I still can't seem to get this to work as I want it to. I have been reading/searching through the book (C++ Primer plus 6th ed.) - I have done some research and still I can't make it wait as I wanted to.
So I have looked at several things here on Stack Overflow for reference: Checking the status of a child process in C++
Here is what I have tried so far:
using namespace std;
int main() {
int status;
pid_t child;
child = fork();
if ( child > 0 ) {
cout << "\nChild #1 is in charge\n";
execlp("ls", "ls", NULL);
}
else if ( child < 0 ) {
cout << "\nSomething wen't wrong in the forking process\n";
}
else {
}
child = fork();
if ( child > 0 ) {
cout << "\nSecond child is in charge\n";
execlp("locate", "locate", "etc", NULL);
}
else if ( child < 0 ) {
cout << "\nSomething went wrong in the forking of second child!\n";
}
else {
}
Now this would show Child #1 is in charge and Second child is in charge then it would mix the two commands (I see some ls in between locate etc).
Second thing I have tried:
using namespace std;
int main() {
int status;
pid_t child;
pid_t ch_status = waitpid(child, &status, WNOHANG);
child = fork();
if ( child > 0 ) {
cout << "\nChild is in charge\n";
execlp("ls", "ls", NULL);
}
else if ( child < 0 ) {
cout << "\nSomething wen't wrong in the forking process\n";
}
if ( ch_status == 0 ) {
}
else if ( ch_status == -1 ) {
cout << "\nERROR IN CHILD #1\n";
}
else {
}
child = fork();
if ( child == 0 ) {
cout << "\nSecond child is in charge\n";
execlp("locate", "locate", "etc", NULL);
}
else if ( child < 0 ) {
cout << "\nSomething went wrong in the forking of second child!\n";
}
if ( ch_status == 0 ) {
}
else if ( ch_status == -1 ) {
cout << "\nERROR IN CHILD #1\n";
}
else {
}
child = fork();
if ( child > 0 ) {
cout << "\nThird child is in charge!\n";
execlp("echo", "echo", "herro", NULL);
}
else if ( child < 0 ) {
cout << "\nForking of third child failed!\n";
}
if ( ch_status == 0 ) {
}
else if ( ch_status == -1 ) {
cout << "\nERROR IN CHILD #2\n";
}
else {
}
return 0;
}
This is more based on the link which I provided, it yielded the same result as the first test run I did, except it would also show ERROR IN CHILD #1/2.
The commands are irrelevant, I just wan't to understand what I am doing wrong here... I have also tried nesting them in else { //start second fork here }, but I got nowhere with this either.
From what I understand after reading the waitpid(2) manual I should be using WNOHANG;
http://linux.die.net/man/2/waitpid
Any suggestions/pointers are greatly appreciated.
If possible, please submit a sample code of how you would accomplish the correct result (execute command 1 -> wait until done -> execute command 2 -> exit).
Look forward to replies.
You should be calling waitpid() in the parent after you fork. That is, it should go into the child > 0 branch.
The function's purpose is to "wait for a change in the child state." However, you're calling it before you spawn a child.
The code should then look like this:
using namespace std;
int main() {
int status;
pid_t child;
child = fork();
if ( child == 0 ) {
cout << "\nChild is in charge" << endl;
execlp("ls", "ls", NULL);
} else if ( child < 0 ) {
cout << "\nSomething wen't wrong in the forking process" << endl;
} else {
cout << "Parent waiting" << endl;
pid_t ch_status = waitpid(child, &status, WNOHANG);
if (ch_status == -1) {
cout << "\nERROR IN CHILD #1" << endl;
}
}
child = fork();
//same procedure as above
}
You are incorrectly judging the order in which output statements executed based on the order their output was flushed. While output can't be flushed until the corresponding statement is executed, you have no flush calls in your code. So flushing can happen much later.
Use endl instead of putting a \n at the end of your lines. The endl manipulator includes a flush.
Related
My problem is that I can't get output from the command line using pipes.
My task: "Redirect the command input stream to cmd.exe | output the result of the cmd.exe command to the main process."
#include <iostream>
#include <windows.h>
using namespace std;
#define deffBuffSize 1024
int funSC() {
HANDLE writeToCL, readFromCL, writeToProcess, readFromProcess;
char lpCmdLine[] = "cmd.exe /k ipconfig";
STARTUPINFOA siA;
PROCESS_INFORMATION piApp;
SECURITY_ATTRIBUTES secAttr;
ZeroMemory(&secAttr, sizeof(SECURITY_ATTRIBUTES));
ZeroMemory(&siA, sizeof(STARTUPINFOA));
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.lpSecurityDescriptor = NULL;
secAttr.bInheritHandle = TRUE;
if (CreatePipe(&readFromCL, &writeToProcess, &secAttr, 0) == 0) {
cout << "Create pipe error :: " << GetLastError() << endl;
return 1;
}
if (!SetHandleInformation(writeToProcess, HANDLE_FLAG_INHERIT, 0)) {
cout << "SetHandleInformation error :: " << GetLastError() << endl;
}
if (CreatePipe(&readFromProcess, &writeToCL, &secAttr, 0) == 0) {
cout << "Create pipe error :: " << GetLastError() << endl;
return 1;
}
if (!SetHandleInformation(readFromProcess, HANDLE_FLAG_INHERIT, 0)) {
cout << "SetHandleInformation error :: " << GetLastError() << endl;
}
siA.cb = sizeof(STARTUPINFOA);
siA.hStdInput = readFromProcess;
siA.hStdOutput = writeToProcess;
siA.hStdError = writeToProcess;
siA.dwFlags = STARTF_USESTDHANDLES;
if (CreateProcessA(NULL, lpCmdLine, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &siA, &piApp) == 0) {
cout << "CreateProcessA error :: " << GetLastError() << endl;
return 1;
}
else {
CloseHandle(readFromProcess);
CloseHandle(writeToProcess);
}
DWORD dRead = 0;
char chBuff[deffBuffSize];
bool bSuccess = FALSE;
memset(chBuff, '\0', deffBuffSize);
string outStd;
bSuccess = ReadFile(readFromCL, chBuff, deffBuffSize, &dRead, NULL);
cout << "bSuccess: " << bSuccess << endl;
cout << "GetLastError: " << GetLastError() << endl;
cout << "Message: " << chBuff;
//CloseHandle(writeToCL);
//CloseHandle(readFromCL);
CloseHandle(piApp.hProcess);
CloseHandle(piApp.hThread);
return 0;
}
int main() {
int result = 0;
result = funSC();
system("pause");
return result;
}
When I execute ReadFile (), I get the result.
ERROR_BROKEN_PIPE (109) - The pipe has been ended.
As I understand it, the pipe is closed at the end of the recording => Question: "Why should CreateProcess() execute "ipconfig" and not output it to an overridden output stream."
I read MSDN, tried to use the ready-made code (for understanding), but this did not lead to a positive result.
Help me please, I will be very happy if I understand how to solve this problem =)
PS: I cannot "close" the console window, because I must have a valid directory (For example: cd anyFolder) If I close the process, I will lose the directory to which the user passed.
This is how I tried to read from the pipe
for (;;) {
bSuccess = ReadFile(readFromCL, chBuff, deffBuffSize, &dRead, NULL);
if (!bSuccess || dRead == 0) {
break;
}
else {
cout << "Message: " << chBuff;
}
}
This endless loop didn't read anything.
P.S : This is the output of a running program, but it only outputs one line of the "ipconfig" command
First, the error of ERROR_BROKEN_PIPE(109) caused by the cmd.exe exit unexpectedly. According to the sample Creating a Child Process with Redirected Input and Output:
The parent process uses the opposite ends of these two pipes to write
to the child process's input and read from the child process's output.
As specified in the STARTUPINFO structure, these handles are also
inheritable. However, these handles must not be inherited. Therefore,
before creating the child process, the parent process uses the
SetHandleInformation function to ensure that the write handle for
the child process's standard input and the read handle for the child
process's standard output cannot be inherited.
You have set the other two handles to be un-inherited, so that cmd.exe exits without an available standard handle.
Set the pipe side of child process instead:
if (!SetHandleInformation(readFromCL, HANDLE_FLAG_INHERIT, 0)) {
cout << "SetHandleInformation error :: " << GetLastError() << endl;
}
if (!SetHandleInformation(writeToCL, HANDLE_FLAG_INHERIT, 0)) {
cout << "SetHandleInformation error :: " << GetLastError() << endl;
}
The issue of content size may because you need to wait for the output from cmd.exe. Add function like: Sleep(1000) before ReadFile Simply could solve it. Then, you could choose the most suitable method to synchronize the input and output of the two processes. Such as read in a for loop:
for (;;) {
memset(chBuff, '\0', deffBuffSize);
bSuccess = ReadFile(readFromCL, chBuff, deffBuffSize, &dRead, NULL);
if (!bSuccess || dRead == 0) {
break;
}
else {
cout << chBuff;
}
}
I have a really simple code where I fork once and the child node mutates with execlp and the parent keeps doing its work. Nothing too fancy.
What I want is to redirect all the standard input to the execlp-ed thread, not the parent.
So if I execute
echo "hi" | ./parent.o
this can be captured with a string s; cin >> s; in some_command.cpp (but not in parent.cpp!).
Current situation (parent.cpp):
int main()
{
int pid = fork();
if (pid < 0) {
std::cout << "Something crashed" << std::endl;
exit(-1);
} else if (pid == 0) {
// We are the forked child
execlp("/some/command", "some_command", NULL);
std::cout << "Execlp failed" << std::endl;
exit(127);
}
// We are the parent, and we keep running
// More stuff...
}
Right now some_command.cpp contains just an empty int main() { }.
Thanks.
wait(), exit() and signals are forbidden
only pipes allowed
A user gives an integer positive number-N and N-processes are created, father creates a child, that child becomes a father and creates another child and so on. Each one of the first processes (N-1) should wait to finish its process-child first and then itself. The initial process should print "1-My Process ID: ", the next process that's been created the number "2 My process ID: and my father's ID:" and so on.
my code. i don't have wait or exit instead i use return(-1).
but i didn't managed to print accordingly the numbers 1 my process id..., 2 my process id..., 3 my process id... and so on.
any ideas?
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
/* Read characters from the pipe and echo them to stdout. */
void read_from_pipe (int file)
{
FILE *stream;
int c;
stream = fdopen (file, "r");
while ((c = fgetc (stream)) != EOF)
putchar (c);
fclose (stream);
}
/* Write some random text to the pipe. */
void write_to_pipe (int file)
{
FILE *stream;
stream = fdopen (file, "w");
fprintf (stream, "\n");
fprintf (stream, " ");
fclose (stream);
}
int main (void)
{
pid_t pid;
int mypipe[2];
int j = 1;
int i;
cout << "\nassume father is by default the first process\n" << "Please enter how child-processes you want: ";
cin >> i;
for( ; j < i; j++)
{
/* Create the pipe. */
if (pipe (mypipe))
{
fprintf (stderr, "Pipe failed.\n");
return (-1);
}
/* Create the child process. */
pid = fork ();
if (pid == (pid_t) 0)
{
/* This is the child process. Close other end first. */
pid = getpid();
close (mypipe[1]);
read_from_pipe (mypipe[0]);
printf("Child's ID: %d\n",pid);
sleep(0);
}
else if (pid > (pid_t) 0)
{
/* This is the parent process. Close other end first. */
pid = getpid();
close (mypipe[0]);
write_to_pipe (mypipe[1]);
printf("Dad's ID: %d\n",pid);
sleep(0);
}
else
{
/* The fork failed. */
fprintf (stderr, "Fork failed.\n");
return (-1);
}
}//end for
//close (mypipe[0]);
//write_to_pipe (mypipe[1]);
// printf("Dad's ID: %d\n",pid);
return (-1);
}// EOP
Recursion could be simpler than iteration because you want each child to in turn create another child. The trick to avoid wait is to have each parent to read on the read end of the pipe, and to have the child to close the write end just before returning without writing anything. Because the read will be blocked until either something has been written or the other end is closed.
You cannot be sure of the order in which the processes will actually end because you do not call wait, but you are sure that a parent cannot end before its childs has terminated its job.
Code could be:
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::cin;
using std::cerr;
using std::endl;
int start_child(int i, int j) {
int my_pipe[2];
pid_t parent_pid, pid;
/* Create the pipe. */
if (pipe (my_pipe))
{
cerr << "Pipe failed." << endl;
return (-1);
}
/* Create the child process. */
parent_pid = getpid();
pid = fork ();
if (pid == (pid_t) 0) {
/* child */
pid = getpid();
close(my_pipe[0]);
cout << "I'm child " << j << "- my pid is " << pid <<
" - my parent's pid is " << parent_pid << endl;
if (i > 1) start_child(i - 1, j + 1);
if (pid == getpid()) cout << "End of child "<< j << endl;
close(my_pipe[1]);
}
else if (pid == (pid_t) -1) {
perror("forking");
close(my_pipe[0]);
close(my_pipe[1]);
return -1;
}
else {
/* parent */
close(my_pipe[1]);
char buf[2];
read(my_pipe[0], buf, 2); // wait for the child to close its pipe end
close(my_pipe[0]);
}
return 0;
}
int main (void)
{
pid_t pid = getpid();
int i;
cout << "\nassume father is by default the first process\n" << "Please enter how child-processes you want: ";
cin >> i;
cout << "I'm parent - my pid is " << pid << endl;
int cr = start_child(i, 1);
if (pid == getpid()) cout << "End of parent" << endl;
return cr;
}// EOP
I'm having some troubles with fork() and that kind of things.
I'm developing a shell, where the user can write commands that whill be executed as in a normal and common shell.
I have a main function like this:
void Shell::init() {
string command;
while (1) {
cout << getPrompt() << " ";
command = readCommand();
if (command.length() > 0) handleCommand(command);
}
}
handleCommand() is the function that does pretty much everything. Somewhere in it, I have the following:
...
else {
pid_t pid;
pid = fork();
char* arg[tokens.size() + 1];
for (int i = 0; i < tokens.size(); ++i) {
arg[i] = (char*) tokens[i].c_str();
}
arg[tokens.size()] = NULL;
if (pid == 0) {
if (execvp(tokens[0].c_str(), arg) == -1) {
cout << "Command not known. " << endl;
};
} else {
wait();
}
}
What I want is that when I reach that point, the command will be treated as a program invocation, so I create a child to run it. It's working almost perfect, but I get the prompt again before the program output. Example:
tronfi#orion:~/NetBeansProjects/Shell2$ whoami
tronfi#orion:~/NetBeansProjects/Shell2$ tronfi
tronfi#orion:~/NetBeansProjects/Shell2$
The child should die after the execvp, so it shouldn't be calling the prompt, and the parent is waiting until the child die.
So... what I'm doing wrong?
Thanks!!
You are calling wait() incorrectly. It expects to be passed a pointer-to-int, in which the child's exit status will be stored:
int status;
wait(&status);
Really, though, you should be using waitpid() to check for the specific child that you're after. You also need to loop around if waitpid() is interrupted by a signal:
int r;
do {
r = waitpid(pid, &status, 0);
} while (r < 0 && errno == EINTR);
I'm not sure that this is exactly the problem, but you must ensure that the child exits even if execvp() fails:
if (pid == 0) {
if (execvp(tokens[0].c_str(), arg) == -1) {
cout << "Command not known. " << endl;
};
exit(1); // or some other error code to indicate execvp() fails
} else {
wait();
}
If you don't do this, then if excecvp() fails then you will end up with two instances of your shell, which is probably not what you want.
The child must be terminated using the call exit(0) (only on success), as this helps in clening of memory and flushes the buffer. This status returned by the child must be checked by the parent and then only it should give the prompt.
Let me know if you need more details.
I am forking a number of processes and I want to measure how long it takes to complete the whole task, that is when all processes forked are completed. Please advise how to make the parent process wait until all child processes are terminated? I want to make sure that I stop the timer at the right moment.
Here is as a code I use:
#include <iostream>
#include <string>
#include <fstream>
#include <sys/time.h>
#include <sys/wait.h>
using namespace std;
struct timeval first, second, lapsed;
struct timezone tzp;
int main(int argc, char* argv[])// query, file, num. of processes.
{
int pCount = 5; // process count
gettimeofday (&first, &tzp); //start time
pid_t* pID = new pid_t[pCount];
for(int indexOfProcess=0; indexOfProcess<pCount; indexOfProcess++)
{
pID[indexOfProcess]= fork();
if (pID[indexOfProcess] == 0) // child
{
// code only executed by child process
// magic here
// The End
exit(0);
}
else if (pID[indexOfProcess] < 0) // failed to fork
{
cerr << "Failed to fork" << endl;
exit(1);
}
else // parent
{
// if(indexOfProcess==pCount-1) and a loop with waitpid??
gettimeofday (&second, &tzp); //stop time
if (first.tv_usec > second.tv_usec)
{
second.tv_usec += 1000000;
second.tv_sec--;
}
lapsed.tv_usec = second.tv_usec - first.tv_usec;
lapsed.tv_sec = second.tv_sec - first.tv_sec;
cout << "Job performed in " <<lapsed.tv_sec << " sec and " << lapsed.tv_usec << " usec"<< endl << endl;
}
}//for
}//main
I'd move everything after the line "else //parent" down, outside the for loop. After the loop of forks, do another for loop with waitpid, then stop the clock and do the rest:
for (int i = 0; i < pidCount; ++i) {
int status;
while (-1 == waitpid(pids[i], &status, 0));
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
cerr << "Process " << i << " (pid " << pids[i] << ") failed" << endl;
exit(1);
}
}
gettimeofday (&second, &tzp); //stop time
I've assumed that if the child process fails to exit normally with a status of 0, then it didn't complete its work, and therefore the test has failed to produce valid timing data. Obviously if the child processes are supposed to be killed by signals, or exit non-0 return statuses, then you'll have to change the error check accordingly.
An alternative using wait:
while (true) {
int status;
pid_t done = wait(&status);
if (done == -1) {
if (errno == ECHILD) break; // no more child processes
} else {
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
cerr << "pid " << done << " failed" << endl;
exit(1);
}
}
}
This one doesn't tell you which process in sequence failed, but if you care then you can add code to look it up in the pids array and get back the index.
The simplest method is to do
while(wait() > 0) { /* no-op */ ; }
This will not work if wait() fails for some reason other than the fact that there are no children left. So with some error checking, this becomes
int status;
[...]
do {
status = wait();
if(status == -1 && errno != ECHILD) {
perror("Error during wait()");
abort();
}
} while (status > 0);
See also the manual page wait(2).
Call wait (or waitpid) in a loop until all children are accounted for.
In this case, all processes are synchronizing anyway, but in general wait is preferred when more work can be done (eg worker process pool), since it will return when the first available process state changes.
I believe the wait system call will accomplish what you are looking for.
for (int i = 0; i < pidCount; i++) {
while (waitpid(pids[i], NULL, 0) > 0);
}
It won't wait in the right order, but it will stop shortly after the last child dies.