This is my code... I don't know why I'm get an error segment... could somebody explain the reason to me?
#include <iostream>
#include <string>
// Required by for routine
#include <sys/types.h>
#include <unistd.h>
using namespace std;
int globalVariable = 2;
main()
{
string sIdentifier;
int iStackVariable = 20;
pid_t pID = vfork();
if (pID == 0) // child
{
// Code only executed by child process
sIdentifier = "Child Process: ";
globalVariable++;
iStackVariable++;
cout << "PROCESO NUMERO"<<getpid()<<sIdentifier;
// printf("Proceso hijo: PID %d - PPID %d\n", getpid(), getppid());
cout << " Global variable: " << globalVariable;
cout << " Stack variable: " << iStackVariable << endl;
return (0);
}
else if (pID < 0) // failed to fork
{
cerr << "Failed to fork" << endl;
return (1);
// Throw exception
}
else // parent
{
// Code only executed by parent process
sIdentifier = "Parent Process:";
}
// executed only by parent
cout << sIdentifier;
cout << " Global variable: " << globalVariable;
cout << " Stack variable: " << iStackVariable << endl;
return (0);
}
Is this of use ? Note the caveats surrounding modification of variables.
The vfork() function has the same effect as fork(), except that the behaviour is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit() or one of the exec family of functions.
If you vfork() both processes are sharing an address space. You should probably only use vfork() if you are going to exec another process pretty much immediately in the child. The reason the system call was created was to avoid the overhead of copying every page in the parent process's address space only to have all those mappings discarded when the child exec's. For your case, use fork() instead.
Related
I am new to multi thread programming, so this question might seem a little silly, but I really need to work this out so I can apply it to my project (which is way more complicated).
Follow is my code, I am trying to have 2 threads (parent and child) to update the same shared timer as they execute and stop when the timer reaches a specific limit.
But when I compile and execute this follow piece of code, there are 2 different outcomes: 1. child prints "done by child at 200000" but the program does not exit; 2. after child prints "done by child at 200000" and exits, parent keeps executing, prints a couple of dozen lines of "parent doing work" and "parent at 190000", then prints "done by parent at 200000" and the program exits properly.
The behavior I want is for whichever thread that updates the timer, hits the limit and exits, the other thread should stop executing and exit as well. I think I might be missing something trivial here, but I've tried changing the code in many ways and nothing I tried seem to work. Any help will be much appreciated :)
#include <iostream>
#include <unistd.h>
#include <mutex>
#include <time.h>
using namespace std;
mutex mtx;
int main () {
int rc;
volatile int done = 0;
clock_t start = clock();
volatile clock_t now;
rc = fork();
if (rc == 0) { //child
while (true) {
cout << "child doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
mtx.unlock();
break;
}
cout << "child at " << now << endl;
mtx.unlock();
}
_exit(0);
}
else { // parent
while (true) {
cout << "parent doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
mtx.unlock();
break;
}
cout << "parent at " << now << endl;
mtx.unlock();
}
}
return 0;
}
Multi-processes
Your code is multi-processes and not multi-threading: fork() will create a new separate process by duplicating the calling process.
The consequence: At the moment of the duplication, all the variables contain the same value in both processes. But each process has its own copy, so a variable modified in the parent will not be updated in the child's address space an vice-versa.
If you want to share variables between processes, you should have a look at this SO question
Multithread
For real multithreading, you should use std::thread. And forget about volatile, because it's not thread safe. Use <atomic> instead, as explained in this awesome video.
Here a first try:
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
#include <time.h>
using namespace std;
void child (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "child doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
}
cout << "child at " << now << endl;
this_thread::yield();
}
}
void parent (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "parent doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
}
cout << "parent at " << now << endl;
this_thread::yield();
}
}
int main () {
atomic<int> done{0};
clock_t start = clock();
atomic<clock_t> now;
thread t(child, std::ref(done), std::ref(now), start); // attention, without ref, you get clones
parent (done, now, start);
t.join();
return 0;
}
Note that you don't need to protect atomic accesses with a mutex, and that if you want to do, lock_guard would be recommended alternative.
This example is of course rather weak, because if you test an atomic variable if the if-condition, it's value might already have changed when entering the if-block. This doesn't cause a problem in your logic where "done" means "done". But if you'd need a more cauthious approach,
compare_exchange_weak() or compare_exchange_strong() could help further.
I am having a bit of trouble getting waitpid to work could someone please explain what is wrong with this code?
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
int main() {
string filename_memory;
decltype(fork()) pid;
if (!(pid = fork())) {
cout << "in child" << endl;
sleep(1);
}
else {
int status_child;
do {
waitpid(pid, &status_child, WNOHANG);
cout << "waiting for child to finish" << endl;
} while (!WIFEXITED(status_child));
cout << "child finished" << endl;
}
return 0;
}
If wait() or waitpid() returns because the status of a child process
is available, these functions shall return a value equal to the
process ID of the child process for which status is reported.
If waitpid() was invoked with WNOHANG set in options, it has at least
one child process specified by pid for which status is not available,
and status is not available for any process specified by pid, 0 is
returned. Otherwise, (pid_t)-1 shall be returned, and errno set to
indicate the error.
This means that the status_child variable has no meaning until waitpid returns the pid of the child.
You can fix this by applying these changes:
int ret;
do {
ret = waitpid(pid, &status_child, WNOHANG);
cout << "waiting for child to finish" << endl;
} while (ret != pid || !WIFEXITED(status_child));
cout << "child finished" << endl;
I am spawning a process in my application:
int status = posix_spawnp(&m_iProcessHandle, (char*)strProgramFilepath.c_str(), NULL, NULL, argsWrapper.m_pBuffer, NULL);
When I want to see if the process is still running, I use kill:
int iReturn = kill(m_iProcessHandle,0);
But after the spawned process has finished its work, it hangs around. The return value on the kill command is always 0. Not -1. I am calling kill from within the code, but if I call it from the command line, there is no error - the spawned process still exists.
Only when my application exits does the command-line kill return "No such process".
I can change this behavior in my code with this:
int iResult = waitpid(m_iProcessHandle, &iStatus, 0);
The call to waitpd closes down the spawned process and I can call kill and get -1 back, but by then I know the spawned process is dead.
And waitpd blocks my application!
How can I test a spawned processes to see if it is running, but without blocking my application?
UPDATE
Thanks for the help! I have implemented your advise and here is the result:
// background-task.cpp
//
#include <spawn.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include "background-task.h"
CBackgroundTask::CBackgroundTask()
{
// Initialize member variables
m_iProcessHandle = 0;
}
CBackgroundTask::~CBackgroundTask()
{
// Clean up (kill first)
_lowLevel_cleanup(true);
}
bool CBackgroundTask::IsRunning()
{
// Shortcuts
if (m_iProcessHandle == 0)
return false;
// Wait for the process to finish
int iStatus = 0;
int iResult = waitpid(m_iProcessHandle, &iStatus, WNOHANG);
return (iResult != -1);
}
void CBackgroundTask::Wait()
{
// Wait (clean up without killing)
_lowLevel_cleanup(false);
}
void CBackgroundTask::Stop()
{
// Stop (kill and clean up)
_lowLevel_cleanup(true);
}
void CBackgroundTask::_start(const string& strProgramFilepath, const string& strArgs, int iNice /*=0*/)
{
// Call pre-start
_preStart();
// Split the args and build array of char-strings
CCharStringAarray argsWrapper(strArgs,' ');
// Run the command
int status = posix_spawnp(&m_iProcessHandle, (char*)strProgramFilepath.c_str(), NULL, NULL, argsWrapper.m_pBuffer, NULL);
if (status == 0)
{
// Process created
cout << "posix_spawn process=" << m_iProcessHandle << " status=" << status << endl;
}
else
{
// Failed
cout << "posix_spawn: error=" << status << endl;
}
// If process created...
if(m_iProcessHandle != 0)
{
// If need to adjust nice...
if (iNice != 0)
{
// Change the nice
stringstream ss;
ss << "sudo renice -n " << iNice << " -p " << m_iProcessHandle;
_runCommand(ss.str());
}
}
else
{
// Call post-stop success=false
_postStop(false);
}
}
void CBackgroundTask::_runCommand(const string& strCommand)
{
// Diagnostics
cout << "Running command: " << COUT_GREEN << strCommand << endl << COUT_RESET;
// Run command
system(strCommand.c_str());
}
void CBackgroundTask::_lowLevel_cleanup(bool bKill)
{
// Shortcuts
if (m_iProcessHandle == 0)
return;
// Diagnostics
cout << "Cleaning up process " << m_iProcessHandle << endl;
// If killing...
if (bKill)
{
// Kill the process
kill(m_iProcessHandle, SIGKILL);
}
// Diagnostics
cout << "Waiting for process " << m_iProcessHandle << " to finish" << endl;
// Wait for the process to finish
int iStatus = 0;
int iResult = waitpid(m_iProcessHandle, &iStatus, 0);
// Diagnostics
cout << "waitpid: status=" << iStatus << " result=" << iResult << endl;
// Reset the process-handle
m_iProcessHandle = 0;
// Call post-stop with success
_postStop(true);
// Diagnostics
cout << "Process cleaned" << endl;
}
Until the parent process calls one of the wait() functions to get the exit status of a child, the child stays around as a zombie process. If you run ps during this time, you'll see that the process is still there in the Z state. So kill() returns 0 because the process exists.
If you don't need to get the child's status, see How can I prevent zombie child processes? for how you can make the child disappear immediately when it exits.
I have the following two simple programs:
bye.cc
#include <iostream>
int main()
{ std::cout << "Bye bye bye world" << std::endl; }
hello.cc
#include <cstdlib>
#include <unistd.h>
#include <sys/wait.h>
#include <iostream>
using namespace std;
int main()
{
int status;
cout << "Hello world" << endl;
int pid = fork();
if (pid != 0) {
cout << "I am parent - " << pid << endl;
// wait for child to finish up......
cout << "Waiting for child to finish" << endl;
wait(&status);
cout << "Child finished, status " << status << endl;
} else {
cout << "--- I am child - " << pid << endl; // **Note**
execl("bye", "");
cout << "--- I am sleeping" << endl;
sleep(3);
exit(11);
}
}
In hello.cc, if the line marked "Note" is enabled (not commented), I get the expected behavior, sleep(3) is not executed, and "bye" is executed, expected msg printed to console.
$ ./hello
Hello world
I am parent - 27318
Waiting for child to finish
--- I am child - 0
Bye bye bye world
Child finished, status 0
However, when the line marked "Note" is commented, "bye" is NOT executed, and sleep(3) is performed.
$ ./hello
Hello world
I am parent - 27350
Waiting for child to finish
--- I am sleeping
Child finished, status 2816
Can someone please help me understand what might be going on. What I found very odd, if I replace the "cout" with a printf(), then the sleep performed.
Thank you,
Ahmed.
According to the spec, the argument list to execl must be terminated by a NULL pointer (i.e. (char *)0, not "").
Changing the nearby code is just changing what happens to be on the stack when you invoke execl. As written, the program's behavior is undefined.
P.S. Always check the return value of library routines for errors.
the exec family of functions, when successful, do not return.
That is why you do not see the sleep comment when the execl() is executed.
As I have just started with these concepts I might be missing out a few elementary things. I was trying to link the parent and the child processes (created by fork() function) using pipe. In the parent process, I wanted to write in the pipe descriptor (af[1]) and after closing up the write end, I wanted to read from the read end of the pipe with descriptor (af[0]) in the child process.
Here is my code:
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <cstdlib>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
using namespace std;
int main()
{
pid_t pid1;
pid1 = fork();
int af[2],nbytes,wbytes;
pipe(af);
char inside[20];
if(pid1 == -1)
{
cout << "No child process formed: " << getpid() <<endl;
exit(1);
}
else if(pid1 == 0)
{ cout<< "inchild" <<endl;
close(af[1]);
nbytes = read(af[0],inside,strlen(inside));
cout << "read bytes: "<< nbytes << endl;
cout << "child(read) inside descriptor: " << inside << endl;
close(af[0]);
cout << "in child's end" << endl;
exit(0);
}
else
{ cout<< "inparent" << endl;
close(af[0]);
wbytes = write(af[1],"Hello World",12);
cout<< "wrote bytes: " << wbytes<<endl;
cout << "Parent(write) inside string: " << af[1] << endl;
close(af[1]);
cout << "in parent's end" << endl;
exit(0);
}
return 0;
}
Then I was expecting this to run as follows:
Goes into the parent -> write string,
Close write end,
Goes into the child -> read string into inside,
Show result of string (Hello World),
Close read end.
But what I was getting here is this result:
inparent
shashish-vm#shashishvm-VirtualBox:~/Desktop$ inchild
read bytes: 0
child(read) inside descriptor:
A��M�N��sf�
in child's end
And it was still not terminating.
I was using Ubuntu 14.04 LTS on Oracle VM VirtualBox (32-bit O.S.). And I have no idea why it was doing like this. I knew it is the job of the scheduler to switch the processes but still pipe functionality of IPC was not working there. The write process occurred even if I removed close(af[0]) statement but still the reading was not happening properly.
You problem is that you open the pipe after calling fork. This means the parent and child have different pipes. You can fix it by moving the call to pipe before the fork to create a single linked pipe.