I'm working on a program that spawns multiple processes via fork() and runs them concurrently. What I want is for the first process that ends to trigger a kill of all the other processes created. I'm getting stuck trying to figure out how to do this. I'm hoping for some suggestions. Here's what I'm thinking so far.
void done(int childid) {
kill(something?,SIGKILL);
printf("process %d signaling\n",childid);
}
int main(int argc, char **argv) {
Signal(SIGCHLD, done);
pid_t pid;
for (each command in an array) {
if ((pid = fork()) == 0) {
setpgid(0,0);
Execve(command stuff);
}
else if (pid > 0) {
printf("starting process %d\n",pid);
}
}
}
Obviously this is rather sudo-coded, but the weird thing is that the ids I get back don't match the ones that started, and obviously the parent program ends before any of the children start returning. I'm just having a very hard time with the logic here. Any help would be greatly appreciated.
Related
So I've been trying to fork a process two times, first fork is to let the main process continue working and the second is to let the child capture the output of the execution of the grand child process. The code is as follow:
void execute_run(char **parameters) {
task_t* task = create_task();
tasks[task_number] = *task;
int pipe_stdout[2];
ASSERT_SYS_OK(pipe(pipe_stdout)); // creating a pipe for stdout
pid_t pid = fork();
ASSERT_SYS_OK(pid);
if (pid == 0) {
// child process
char buffer[MAXLENGTH_OUTPUT];
pid = fork();
ASSERT_SYS_OK(pid);
if (pid == 0) {
// this process will redirect stdout to buffer
const char* program_name = parameters[0];
char** program_args = ¶meters[1];
ASSERT_SYS_OK(close(pipe_stdout[0]));
ASSERT_SYS_OK(dup2(pipe_stdout[1], STDOUT_FILENO));
// redirecting stdout to pipe
ASSERT_SYS_OK(close(pipe_stdout[1]));
ASSERT_SYS_OK(execvp(program_name, program_args));
}
else {
ASSERT_SYS_OK(close(pipe_stdout[1]));
int status;
do
{
// this loop runs forever
} while (waitpid(pid, &status, WNOHANG) == 0);
ASSERT_SYS_OK(close(pipe_stdout[0]));
// this is never printed
fprintf(stderr, "Child process finished with status %d\n", status);
}
} else {
// parent process won't use any of the pipe ends
ASSERT_SYS_OK(close(pipe_stdout[0]));
ASSERT_SYS_OK(close(pipe_stdout[1]));
}
}
char** parameters are ['cat', 'in.txt'] in the example i'm trying to run (and file exists).
Thanks in advance!
I've tried debugging it and running with different commands like 'ls' for which it works fine, nevertheless I can't figure out why with 'cat' it doesn't work
I asked quesiton, before this. And Thanks to help from others, I made sample code that runs bc command continuously until I enter '1'.
In this code, I use tcsetpgrp() to give child the control of terminal.
When I run the code, bc command works well. However, when I enter 'quit', child process receives SIGSTP and code is ended. (What I want is continuing while loop!!)
int main()
{
while(1){
int n;
scanf("%d", &n);
execute();
if (n == 1)
break;
}
}
void execute()
{
char *args[] = {"bc", 0};
pid_t pid = fork();
if (pid == 0){
execvp("bc", args);
}
if (pid > 0){
setpgid(pid, pid);
tcsetpgrp(STDIN_FILENO, getpgid(pid);
wait(0);
}
}
I think that I should change child to background and parent to foreground after execvp. However, after execvp function, child process terminates, so it seems possible to do that.
So, I also added
signal(SIGSTP, handler);
where handler function is
void handler(int sig){
tcsetpgrp(STDIN_FILENO, getpgid(getppid()));
exit(0);
}
However, handler function does not executed when I enter 'quit' while bc command is executed.
So, now, I don't know how to solve it. I really want to handle this problem. Please help me..
I have this snippet code, and I would like to determine how many processes run_morecompute. I am learning OS and I am struggling with the concept of forking.
Thank you
void run_morecompute(int i){
printf("hello world");
}
void run_compute(int i) {
int cpid = fork();
if (cpid == 0)
run_morecompute(i);
}
int main (){
int pid;
for (int i = 0; i < 4; i++) {
pid = fork();
if (pid == 0){
printf("\n%d",i);
run_compute(i);
}
}
}
If you change
printf("hello world");
to
printf("hello world from %d", getpid());
It will add the process ID to the output. It may help you understand how many processes get created.
I'd suggest changing the loop in main to just call run_morecompute() until you get a handle on what is happening. The additional fork() in run_compute() makes things more complicated.
The top level process forks 4 child processes that call run_compute(). Those 4 children then become parents and fork 3 more children each. Then those 12 children fork 2 more processes each... etc.
Hope that helps.
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).
In the code below, do the forks actually run in parallel or one after another?
What is the meaning of wait(NULL) ?
(The program creates an n number of child processes, n is supplied via command line)
int main ( int argc, char *argv[] ) {
int i, pid;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
if(pid < 0) {
printf("Error occured");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
exit(0);
} else {
wait(NULL);
}
}
}
They do run in parallel, up until the point that one of them waits.
wait(NULL) or more accurately wait(0) means wait until a state change in the child process. To find out about Unix / Linux C api calls, type man <function Name> on the command line. You'll need to get used to reading those pages, so better start now.
In your case
man wait
would have given you what you needed.
Since you've only fork(...)ed once, you have only one child. The parent waits until it changes state, and since the child's state during the fork is the same as the parent's state prior to the fork (that of running), the likely outcome is that the parent waits until the child dies. Then the parent will continue executing, but since it doesn't have much to do after the wait(...) call, it will quickly exit too.