I'm trying to write sort function.
This function may fork many children to help itself to sort the given input.
When my function has only one child it is easy to use pipe(). I just create
int fd[2];
then everything is fine but I don't know what to do when there are many children. Should I create fd[Children*2] pipes or fd[2] is enough?
And how can i use these pipes to communicate with the child that I want (since there are many children)?
My main process will fork children, this is just one part of the code, I'm forking children and getting their pids into pid array
pid_t main = getpid();
int N = 30;
pid_t* children = (pid_t*) malloc(sizeof(pid_t) * N);
for(i = 0; i < N; i++){
pid_t child = fork();
if ( child == 0){
pid_t me = getpid();
printf("I'm a child and my pid is: %d\n", me);
sleep(1);
// exit(4);
return me * 2;
} else if ( child < 0){
// printf("Could not create child\n");
} else {
children[i] = child;
// printf("I have created a child and its pid %d\n", child);
}
}
If only the main process needs to create and communicate with children, and the children don't need to communicate with each other, create a separate pipe for each child in the main process before forking the child. The call to pipe() could be placed in your loop, before calling fork(). You could use a 2-dimensional array like fd[NUM_CHILDREN][2] to keep track of the file descriptors. If the data will be arriving asynchronously, poll() or select() can be used to find out when something is available to be read.
Related
I have to Test argv by modifying this code and I have no idea what the question is asking me... I am just learning and very new to this whole thing.
use fork to create a new process which will print its copy of argv. The
parent process should also print its own copy of argv. Run the program and direct the
output to a temp file. Open the temp file and check if both child and parent processes
print the same set of arguments. Make sure the parent waits for its child before it
terminates.
int printList(char **someList)
{
int index=0;
while(someList[index]!=NULL)
{
printf("%s\n "someList[index]);
index++;
}
return index;
}
int main (int argc, char **argv, char **envp)
>{...
}```
In Linux, forking a process spawns a new "child process" which is an exact copy of the memory and state of execution of the parent (except the return value of the fork() call itself will be different). So your question is asking you to do something like
int main (int argc, char **argv, char **envp)
{
int pid = fork();
int output_fd = file.open("temp.txt")
if(pid == 0) {//This is the child process
fprintf(output_fd, "I am the child, my args are %s", argv);
exit(0);
}
//This is the parent process, wait for child to terminate then print argv
wait(pid);
fprintf(output_fd, "I am the parent, my args are %s", argv);
}
In the output file, you should see the both the parent and child process printed their args and that they have the same argv, because memory is copied from parent to child process when you make a fork() call.
I'm currently learning how to use system calls such as fork, exec*, and kill. I had a task that required to send SIGKILL to all parent's sibilngs created with fork if one of fork calls failed. So I did smth like this:
for (int i = 0; i < numOfchilds; i++) {
childs[i] = fork();
if (childs[i] == -1)
killAll(childs, i);
...
void killAll(pid_t childs, size_t numOfChilds) {
for (int i = 0; i < numOfChilds; i++)
kill(childs[i], SIGKILL);
}
But I messed up and accidentally send kill(-1, SIGKILL) and killed all processe that I could. Fortunately I didn't lose any unsave data, but kill -9 -1 is not the best practice to logout.
So. Is there any way I can restrict my program killing any processes that don't belong to it, so it could only kill one it created with fork?
Suppose I have 10 child processes which are moved to their own process group by setpgid(0,0) just before the exec. (Each child also has children which are also in their own process group.)
My foreground process gets ctrl-c SIGINT signal and I want to propagate it to the all child processes (all children are in different group). How to do that?
hope that quick draft better explain my problem.
void handler(int signal) {
// resend SIGINT to all childs but childs are in different pgid
}
int main(int argc, char* argv[]){
struct sigaction sa;
sa.sa_handler = &handler;
sigaction(SIGINT, &sa, NULL);
pid_t pid[SIZE];
int i = 0;
// if argv is ge 2;
for (;i < SIZE; i++) // SIZE is number of the elements in argv
{
pid[i] = fork();
if(pid[i] == 0)
{
setpgid(0,0);
// execv self here but with one less element in argv;
}
}
while(1){}; // infinity loop (waits for ctrl-c from foreground process)
// prints to the terminal pid and pgid
// waits here for all childs to finish and then close self
}
What about forwarding the signal in the signal handler of main process, manually. Maybe you can provide some code snippet to clarify the situation you're in.
void signalHandler(int signum)
{
kill(child_pid,signum);
//other stuff
}
I am creating a shell command from the custom shell to do the ssh from one terminal to another terminal.
In order to do the ssh, I am using the inbuilt ssh command of the linux. Here is my code that does the ssh login.
However, I am seeing that the I/O buffers are not in sync.
This is what I am seeing on the terminal. After SSH to the other terminal. I did the following in the terminal.
PRT# ssh 192.168.10.42
PRT# Could not create directory '/root/.ssh'.
root#192.168.10.42's password:
# screen -r
-sh: cen-: not found
# hello
-sh: el: not found
#
I don't what's the reason here. Here is the code.
int sshLogin(chr *destIp)
{
char cmd[CMD_LEN];
char readbuff[CMD_LEN];
pid_t pid;
int ret = 0;
int fd[2];
int result;
memset(cmd,'\0',sizeof(cmd));
int status = 0;
/** --tt required to force pseudowire allocation because we are behind screen app **/
sprintf(cmd,"/usr/bin/ssh -tt %s",destIp);
/** create a pipe this will be shared on fork() **/
pipe(fd);
if((pid = fork()) == -1)
{
perror("fork:");
return -1;
}
if( pid == 0 )
{
/** Child Process of Main APP --Make this parent process for the command**/
if((pid = fork()) == -1)
{
perror("fork:");
return -1;
}
if( pid == 0)
{
/** basically Main APP grand child - this is where we running the command **/
ret = execlp("ssh", "ssh", "-tt", destIp, NULL);
printf("done execlp\r\n");
}
else
{
/** child of Main APP -- keep this blocked until the Main APP grand child is done with the job **/
while( (read(fd[0], readbuff, sizeof(readbuff))))
{
printf("%s",readbuff);
}
waitpid(0,&status,0);
LOG_STRING("SSH CONNC CLOSED");
exit(0);
}
}
else
{
/** Parent process APP MAIN-- **/
/** no need to wait let APP MAIN run -- **/
}
return 0;
}
Based on Patrick Ideas.
POST 2# - It seems that it works when we close the stdin in the parent process. However, it becomes very slugguish, I feel like I am typing the keyboard too slow. The system becomes too sluggish. Also, I have a web-server from this terminal. I see that I can no longer access the web.
So, the solution is somewhere around stdin but I am not sure.
int sshLogin(chr *destIp)
{
char cmd[CMD_LEN];
char readbuff[CMD_LEN];
pid_t pid;
int ret = 0;
int fd[2];
int result;
memset(cmd,'\0',sizeof(cmd));
int status = 0;
/** --tt required to force pseudowire allocation because we are behind screen app **/
sprintf(cmd,"/usr/bin/ssh -tt %s",destIp);
/** create a pipe this will be shared on fork() **/
pipe(fd);
if((pid = fork()) == -1)
{
perror("fork:");
return -1;
}
if( pid == 0 )
{
/** Child Process of Main APP --Make this parent process for the command**/
if((pid = fork()) == -1)
{
perror("fork:");
return -1;
}
if( pid == 0)
{
/** basically Main APP grand child - this is where we running the command **/
ret = execlp("ssh", "ssh", "-tt", destIp, NULL);
printf("done execlp\r\n");
}
else
{
/** child of Main APP -- keep this blocked until the Main APP grand child is done with the job **/
while( (read(fd[0], readbuff, sizeof(readbuff))))
{
printf("%s",readbuff);
}
waitpid(0,&status,0);
LOG_STRING("SSH CONNC CLOSED");
exit(0);
}
}
else
{
/** Parent process APP MAIN-- **/
/** no need to wait let APP MAIN run -- **/
close(stdin);
}
return 0;
}
Basically, I have added - close(stdin);
You have 2 different processes trying to read from STDIN. This causes process 1 to get char 1, process 2 to get char 2, process 1 to get char 3, process 2 to get char 4, etc, alternating back and forth.
Your 2 processes are:
execlp("ssh", "ssh", "-tt", destIp, NULL);.
while( (read(fd[0], readbuff, sizeof(readbuff))))
Basically you need to ditch the read(fd[0],...).
My initial thought is that perhaps it is buffering the output: stdout is buffered, so unless you print a newline, nothing will be printed until a certain number of characters build up. This is because I/O operations are expensive. You can find more detail on this here. The result is that there is a delay because your program is waiting to print.
My suggestion: in your main function, before calling your sshLogin function, try disabling buffering with this line of code:
setbuf(stdout, NULL);
You can also call fflush(stdout); periodically to do the same thing, but the above method is more efficient. Try it and see if that solves your problem.
I am trying to create multiple processes from a same parent, but it always ended up with more processes than expected. I couldn't figure out how to do it and need some help here.
I found a piece of code online and tried it,
int main ()
{
pid_t pid=0;
int i=0;
for (i=0; i<3; i++)
{
pid=fork();
switch(pid)
{
case 0:
{
cout<<"\nI am a child and my pid is:"<<getpid();
cout<<endl;
exit(0);
break;
}
default:
{
cout<<"\nI am a parent and my pid is: "<<getpid();
cout<<"\nMy child pid is: "<<pid;
cout<<endl;
wait(NULL);
break;
}
}
}
return 0;
}
This code does work and creates 3 children from same parent. However, it seems like that's because after each child process was created, it was terminated immediately. So it won't fork more grandchild process in the next round of for loop. But I need to keep these child processes running for sometime and they need to communicate with the parents.
A child process may immediately break the loop to continue its work outside
int main ()
{
cout<<"\nI am a parent and my pid is: "<<getpid()<<endl;
pid_t pid;
int i;
for (i=0; i<3; i++)
{
pid=fork();
if(pid == -1)
{
cout<<"Error in fork()"<<endl;
return 1;
}
if(pid == 0)
break;
cout<<"My child "<<i<<" pid is: "<<pid<<endl;
}
if(pid == 0)
{
cout<<"I am a child "<<i<<" and my pid is "<<getpid()<<endl;
wait(NULL); // EDIT: this line is wrong!
}
else
{
cout<<"I am a parent :)"<<endl;
wait(NULL); // EDIT: this line is wrong!
}
return 0;
}
EDIT
The wait(NULL) lines are wrong. If the process has no children active, wait() has no effect, so it's useless in children here. OTOH in the parent process wait() suspends the execution until any of children exits. We have three children here, so would have to wait() three times. Additionally one can't know in advance the order of children completion, so we would need much more sophisticated code for that. Something like this:
struct WORK_DESCRIPTION {
int childpid;
// any other data - what a child has to do
} work[3];
for(i=1; i<3; i++) {
pid=fork();
...
work[i].childpid = pid;
}
if(pid == 0) // in a child
{
do_something( work[i] );
}
else
{
int childpid;
while(childpid = wait(NULL), childpid != 0)
{
// a child terminated - find out which one it was
for(i=0; i<3; i++)
if(work[i].childpid == childpid)
{
// use the i-th child results here
}
}
// wait returned 0 - no more children to wait for
}