understanding forking - simple - c

if I have a program like this:
int i = 0;
int status;
bool result = true;
for(i = 0; i < numfiles; i++) { // LOOP 1
if (fork() == 0) {/* Child */
if (substLines(s1, s2, filenames[i])) {
exit(0);
} else {
exit(2);
}
}
}
for(i = 0; i < numfiles; i++) { // LOOP 2
wait(&status);
....
}
return result;
}
I have the following question.
what happens if a child process exists, before the program even knows about the wait(). I guess my question is regarding how a program is 'read'. Again, for example. If I exit from the first child, whilst still going through LOOP 1, what happens (does it even know about LOOP 2 at this point)?
is this a concurrent program? the parent seems to be waiting on the children after is forked them all, so i would say yes?

The man page of wait says
If a child has already changed state, then these calls return immediately. Otherwise they block until either a child changes state or a signal handler interrupts the call
so question1 doesn't matter
and question2, the answer is no.
Concurrency means they are running at the same time. It needs mutil-core CPU or more than one computer such as distributed system.
your program is multi-process, it is just Parallelism, which means they are running one by one under the schedule of CPU, for more info: Scheduling_(computing)

Just an addition to #simon_xia's excellent answer.
A killed or exited process becomes a zombie until its parent calls wait for it. And yes, this is the official terminology. :-) In zombie state everything is cleaned up (memory pages, open files, env, etc), just the exit status or killing signal number are kept.

Related

Getting exit status of child process without wait()? [duplicate]

I have a program that uses fork() to create a child process. I have seen various examples that use wait() to wait for the child process to end before closing, but I am wondering what I can do to simply check if the file process is still running.
I basically have an infinite loop and I want to do something like:
if(child process has ended) break;
How could I go about doing this?
Use waitpid() with the WNOHANG option.
int status;
pid_t result = waitpid(ChildPID, &status, WNOHANG);
if (result == 0) {
// Child still alive
} else if (result == -1) {
// Error
} else {
// Child exited
}
You don't need to wait for a child until you get the SIGCHLD signal. If you've gotten that signal, you can call wait and see if it's the child process you're looking for. If you haven't gotten the signal, the child is still running.
Obviously, if you need to do nothing unitl the child finishes, just call wait.
EDIT: If you just want to know if the child process stopped running, then the other answers are probably better. Mine is more to do with synchronizing when a process could do several computations, without necessarily terminating.
If you have some object representing the child computation, add a method such as bool isFinished() which would return true if the child has finished. Have a private bool member in the object that represents whether the operation has finished. Finally, have another method private setFinished(bool) on the same object that your child process calls when it finishes its computation.
Now the most important thing is mutex locks. Make sure you have a per-object mutex that you lock every time you try to access any members, including inside the bool isFinished() and setFinished(bool) methods.
EDIT2: (some OO clarifications)
Since I was asked to explain how this could be done with OO, I'll give a few suggestions, although it heavily depends on the overall problem, so take this with a mound of salt. Having most of the program written in C style, with one object floating around is inconsistent.
As a simple example you could have a class called ChildComputation
class ChildComputation {
public:
//constructor
ChildComputation(/*some params to differentiate each child's computation*/) :
// populate internal members here {
}
~ChildComputation();
public:
bool isFinished() {
m_isFinished; // no need to lock mutex here, since we are not modifying data
}
void doComputation() {
// put code here for your child to execute
this->setFinished(true);
}
private:
void setFinished(bool finished) {
m_mutex.lock();
m_isFinished = finished;
m_mutex.unlock();
}
private:
// class members
mutex m_mutexLock; // replace mutex with whatever mutex you are working with
bool m_isFinished;
// other stuff needed for computation
}
Now in your main program, where you fork:
ChildComputation* myChild = new ChildComputation(/*params*/);
ChildPID= fork();
if (ChildPID == 0) {
// will do the computation and automatically set its finish flag.
myChild->doComputation();
}
else {
while (1) { // your infinite loop in the parent
// ...
// check if child completed its computation
if (myChild->isFinished()) {
break;
}
}
// at the end, make sure the child is no runnning, and dispose of the object
// when you don't need it.
wait(ChildPID);
delete myChild;
}
Hope that makes sense.
To reiterate, what I have written above is an ugly amalgamation of C and C++ (not in terms of syntax, but style/design), and is just there to give you a glimpse of synchronization with OO, in your context.
I'm posting the same answer here i posted at as this question How to check if a process is running in C++? as this is basically a duplicate. Only difference is the use case of the function.
Use kill(pid, sig) but check for the errno status. If you're running as a different user and you have no access to the process it will fail with EPERM but the process is still alive. You should be checking for ESRCH which means No such process.
If you're running a child process kill will succeed until waitpid is called that forces the clean up of any defunct processes as well.
Here's a function that returns true whether the process is still running and handles cleans up defunct processes as well.
bool IsProcessAlive(int ProcessId)
{
// Wait for child process, this should clean up defunct processes
waitpid(ProcessId, nullptr, WNOHANG);
// kill failed let's see why..
if (kill(ProcessId, 0) == -1)
{
// First of all kill may fail with EPERM if we run as a different user and we have no access, so let's make sure the errno is ESRCH (Process not found!)
if (errno != ESRCH)
{
return true;
}
return false;
}
// If kill didn't fail the process is still running
return true;
}

Synchronising processes with semaphores

I'm having a tricky time understanding how to alternate control between two processes using semaphores. Here's a contrived example of the process handling code.
int pid = fork();
if (pid) {
int counter = 0;
while (true) {
counter += 1;
printf("P%d = %d", pid, counter);
}
} else {
int counter = 0;
while (true) {
counter += 1;
printf("P%d = %d", pid, counter);
}
}
I was expecting the above code to run in parallel, but it seems like control flow continues instantly for the forked process and only later resumes for the parent process.
This is fundamentally breaking my existing code that uses a semaphore to control which process can act.
int id = get_semaphore(1);
int pid = fork();
if (pid) {
int counter = 0;
while (true) {
sem_wait(id);
counter += 1;
printf("P%d = %d\n", pid, counter);
sem_signal(id);
}
} else {
int counter = 0;
while (true) {
sem_wait(id);
counter += 1;
printf("P%d = %d\n", pid, counter);
sem_signal(id);
}
}
The sem_wait helper just subtracts 1 from the semaphore value and blocks until the result is > 0 (uses semop under the hood).
The sem_signal helper just adds 1 to the semaphore value (uses semop under the hood).
I'd like the code to alternate between the two processes, using sem_wait to block until the other process releases the resources with sem_signal. The desired output would be:
P1 = 0
P0 = 0
P1 = 1
P0 = 1
...
However, because of the initial execution delay between the processes, the child process takes the available semaphore resource, uses it to print a number, then restores it and loops — at which point the resource is available again, so it continues without ever waiting for the other process.
What's the best way to prevent a process from using resources if it released them itself?
it seems like control flow continues instantly for the forked process and only later resumes for the parent process
That is because stream IO buffers the output on stdout until either
the buffer is full
fflush() is called on stdout
a newline (\n) is encountered
In your program, each process will fill a buffer before sending its contents to stdout giving the appearance of one process running for a long time, then the other. Terminate the format strings of your printf statements with \n and you'll see behaviour in your first program more like you expect.
I am not sure why your semaphore thing isn't working - I'm not very knowledgeable about system V semaphores but it seems like a red flag to me that you are getting the semaphore after you have forked. With the more common POSIX semaphores, the semaphore has to be in memory that both processes can see otherwise it's two semaphores.
Anyway, assuming your get_semaphore() function does the right thing to share the semaphore, there is still a problem because there is no guarantee that, when one process signals the semaphore, the other one will start soon enough for it to grab it again before the first process loops round and grabs it itself.
You need two semaphores, one for the parent and one for the child. Before the print each process should wait on its own semaphore. After the print, each process should signal the other semaphore. Also, one semaphore should be initialised with a count of 1 and the other should be initialised with a count of 0.
Semaphores have two general use cases. One is mutual exclusion and the second is synchronization. What's been done in your code is mutual exclusion. What you actually want is synchronization (alternation) between the parent and child processes.
Let me explain a bit:
Mutual exclusion means that at any time only once process can access a "critical section" which is a piece of code that you want only one process/thread to access at a time.Critical sections generally have a code that manipulates a shared resource.
Coming to your code, since you have used only a single semaphore, there is no guarantee as to the "order" in which each process is allowed to enter the critical section.
ex: sem_wait(id) from your code can be executed by any process and it's not necessary that the two processes should alternate.
For process synchronization (more specifically alternation), you need to use two semaphore one for parent and another for child.
Sample code:
int pid = fork();
int parent_sem = get_semaphore(0);
int child_sem = get_semaphore(1);
if (pid) {
int counter = 0;
while (true) {
sem_wait(child_sem);
counter += 1;
printf("P%d = %d", pid, counter);
sem_signal(parent_sem);
}
} else {
int counter = 0;
while (true) {
sem_wait(parent_sem);
counter += 1;
printf("P%d = %d", pid, counter);
sem_signal(child_sem);
}
}
You need to initialize one semaphore (in my case child) to 1 and the second one to zero. That way only of the two processes get to start while the other enters into wait. Once child is done printing, it signals the parent. Now child's semaphore value is zero so it waits on wait(child_sem) while the parent that was signaled by the child executes. Next time, parent signals child and it executes. This continues in alternating sequences and is a classic synchronization problem.

Make child process wait for parent

I have to write a program in C that will fork a new process and then use that processes pid for another function. However I need to call this function before the child process can run and I don't know how to do this.
Here's some pseudo code of what I'm trying to do.
pid_t pid = fork();
if(in_child){ //In the child process
//launch child application
//somehow stop the child application before it actually executes any code
}
else{
//call my function with the child's pid
//resume the child process
//do other stuff
}
If you need any additional info please ask. Thanks.
Edit: I do not have access to the code for the child. I'm just wanting to run an executable.
If you mean any code at all, that can be difficult. You can use clone with CLONE_STOPPED instead of fork to start the application into a stopped state (needing SIGCONT to get it going again).
However, if you simply mean specific code in the child and you can modify the child code, you can, as the first thing in main, simply set up a handler for a USR1 signal (any IPC would probably do but a signal seems the simplest in this particular case) and then wait for it to fire before carrying on.
That way, the process itself will be running but won't be doing anything yet.
You then have the parent weave whatever magic it needs to do, then send a SIGUSR1 to the child.
But since, according to a comment, you don't have access to the client code, the first option may be the best, assuming that SIGCONT won't actually cause problems with the child. That will require testing.
Of course, one thing to keep in mind is that neither clone() nor fork() will actually load your new program into the child process, that has to be done with an exec-type call after the split. This is a result of the UNIX split between fork and exec functionality, detailed here.
That means that, while you don't control the child program, you do control the child process, so your code can wait for whatever signal it wants before loading up the new child program. Hence it's doable even with just fork().
Unfortunately, that also means that neither clone nor fork can stop your process after the new program has been loaded with exec (at least not deterministically) so, if the fiddling you want to do is to the new program (such as manipulating its variables by attaching to its memory), you can't do it.
The best you can do is to fiddle with the new process while it still has a copy of the old program (before the exec).
There's a simpler way, assuming your OS will let you share the address space before the child execs. Pseudo-code follows.
volatile int barrier;
int safe_fork(routine_to_call)
{
pid_t pid;
barrier = 0;
pid = fork();
if (pid == 0) {
/* parent */
routine_to_call()
barrier = 1;
} else if (pid > 0) {
while (barrier = 0)
; /* or sleep if it's a slow routine */
exec()
//if we get here, exec failed; exit with failure code
} else {
/* return failure */
}
/* must be parent; return success */
}
You may need to do something special to get the sharing behaviour, rather than having them both start with independent copies. I know it's doable on FreeBSD. In linux, check out the CLONE_VM flag to clone(); it looks like it should let you do what you need here.
What you are looking for is interprocess condition variable.
https://en.wikipedia.org/wiki/Monitor_(synchronization)
The way it would work (roughly) :-
Before forking you set a variable asking child to wait :- child_continue = false
1.) CHILD process begins to execute (or parent, doesn't matter)
If the variable child_continue == false
Sleep on a condition variable and wait for signal from parent
2.) Parent process waits for its chance to run (note the order of run doesn't matter). When the parent process is ready to run, it does whatever it wants with the child PID (or something else) and signals the child process to continue.
In order to do this, you'd need interprocess mutex and interprocess condition variable.
//#include "pthread.h" in main file
//create IPC MUTEX which can be shared by both child and parent.
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
pthread_mutex_t mtx;
pthread_cond_t cond;
if (0!= pthread_mutexattr_init(&mutex_attr))
{
//errror handling
}
if (0!= pthread_condattr_init(&cond_attr))
{
//errror handling
}
if (0 != pthread_condattr_setpshared(&cond_attr,PTHREAD_PROCESS_SHARED)
{
//error handling
}
if (0 != pthread_mutexattr_setpshared(&mutex_attr,PTHREAD_PROCESS_SHARED)
{
//error handling
}
if (0 !=pthread_mutex_init(&mtx,&mtx_attr))
{
//error handling
}
if (0 !=pthread_cond_init(&cond,&cond_attr))
{
//error handling
}
boolean child_continue = false;
//now fork !!
pid_t pi = fork();
if (pi ==0) //child
{
if (0 !=pthread_mutex_lock(&mtx))
{
//error handling
}
while (!child_continue) //wait until we receive signal from parent.
{
if (0 !=pthread_cond_wait(&cond,&mtx))
{
//error handling
}
}
if (0 !=pthread_mutex_unlock(&mtx))
{
//error handling
}
//Parent is done!! either we woke up by condition variable or, parent was done before hand
//in which case, child_continue was true already.
}
else
{
//in parent process do whatever you want with child pid (pi variable)
//once you are done, set child_continue to true and wake up child.
if (0 !=pthread_mutex_lock(&mtx))
{
//error handling
}
child_continue = true;
if (0 !=pthread_cond_signal(&cond))
{
//error handling
}
if (0 !=pthread_mutex_unlock(&mtx))
{
//error handling
}
}

Is this busy waiting?

Is this loop busy waiting, I would think the wait call takes care of that. If it is, how can it be fixed to not busy wait?
id = fork();
for (i = 0; i < 20; i++)
{
switch (id)
{
case 0:
/* do stuff with child */
exit(0);
default:
{
if (children>=3) {
int s;
wait(&s);
children--;
}
children++;
id = fork();
}
}
}
wait will cause the kernel to select other jobs that are not marked as blocked, so this isn't a case of busy-waiting. Also isn't switch a bit excessive for a fork(), why not use a simple if statement?
You are right, wait waits non-busy by handing over the CPU to the kernel until the child has exited.
It's not really buys waiting (it doesn't check the status of the children in a loop; instead if blocks inside the wait() call).
Nonetheless, the code can hog the CPU depending on what happens in do stuff with child. That will look like busy waiting (CPU usage 100%) even though it's really several processes doing actual work.
I agree with you, waiting on the death of a child (even inside a loop) would not be busy waiting. OTOH you can get in real trouble if one or more of the child processes are compute intensive. The compute-intensive children will always be ready to run and it is not guaranteed that the parent will get the CPU.

Multiple fork() Concurrency

How do you use the fork() command in such a way that you can spawn 10 processes and have them do a small task concurrently.
Concurrent is the operative word, many places that show how to use fork only use one call to fork() in their demos. I thought you would use some kind of for loop but i tried and it seems in my tests that the fork()'s are spawning a new process, doing work, then spawning a new process. So they appear to be running sequentially but how can I fork concurrently and have 10 processes do the work simultaneously if that makes sense?
Thanks.
Update: Thanks for the answers guys, I think I just misunderstood some aspects of fork() initially but i understand it now. Cheers.
Call fork() in a loop:
Adding code to wait for children per comments:
int numberOfChildren = 10;
pid_t *childPids = NULL;
pid_t p;
/* Allocate array of child PIDs: error handling omitted for brevity */
childPids = malloc(numberOfChildren * sizeof(pid_t));
/* Start up children */
for (int ii = 0; ii < numberOfChildren; ++ii) {
if ((p = fork()) == 0) {
// Child process: do your work here
exit(0);
}
else {
childPids[ii] = p;
}
}
/* Wait for children to exit */
int stillWaiting;
do {
stillWaiting = 0;
for (int ii = 0; ii < numberOfChildren; ++ii) {
if (childPids[ii] > 0) {
if (waitpid(childPids[ii], NULL, WNOHANG) != 0) {
/* Child is done */
childPids[ii] = 0;
}
else {
/* Still waiting on this child */
stillWaiting = 1;
}
}
/* Give up timeslice and prevent hard loop: this may not work on all flavors of Unix */
sleep(0);
}
} while (stillWaiting);
/* Cleanup */
free(childPids);
When you fork off processes the WILL be running concurrently. But note that unless you have enough available idle processors, they might not actually be executing concurrently, which shouldn't really matter...
Your second paragraph makes it seem like you aren't understanding how fork works, you have to check the return code to see if you are in the parent or in the forked process. So you would have the parent run a loop to fork off 10 processes, and in the children you do whatever you wanted to do concurrently.
Just loop in the "main" process spawning one child after another with each assign a particular task.
You might also want to look into POSIX Threads (or pthreads). Here is a tutorial:
https://computing.llnl.gov/tutorials/pthreads/

Resources