The question is given like this:
Using the CreateProcess () in the Win32 API. In this instance, you will need to specify a separate program to be invoked from CreateProcess(). It is this separate program that will run as a child process outputting the Fibonacci sequence. Perform necessary error checking to ensure that a non-negative number is passed on the command line.
I have done the following. It doesn't show any error message. When I try to execute it, it exits automatically:
#include <sys/types.h>
#include <windows.h>
#define _WIN32_WINNT 0x0501
#include <stdio.h>
int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
int a=0, b=1, n=a+b,i,ii;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
if(! CreateProcess("C:\\WINDOWS\\system32\\cmd.exe",NULL,NULL,NULL,FALSE,0,
NULL,NULL,&si,&pi))
printf("\nSorry! CreateProcess() failed.\n\n");
else{
printf("Enter the number of a Fibonacci Sequence:\n");
scanf("%d", &ii);
if (ii < 0)
printf("Please enter a non-negative integer!\n");
else
{
{
printf("Child is producing the Fibonacci Sequence...\n");
printf("%d %d",a,b);
for (i=0;i<ii;i++)
{
n=a+b;
printf("%d ", n);
a=b;
b=n;
}
printf("Child ends\n");
}
{
printf("Parent is waiting for child to complete...\n");
printf("Parent ends\n");
}
}
}
WaitForSingleObject(pi.hProcess, 5000);
printf("\n");
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
What am I doing wrong?
I think you misunderstood your exercise. Also, you might want to do handle inheritance while using CreateProcess. This might be above your skill level, but still a useful lesson:
http://support.microsoft.com/kb/q190351/
Why are you invoking cmd.exe as your process? The problem states that it's the process that you're launching that should be printing the Fibonacci sequence. You shouldn't be doing it in the main process/app.
What you should have is a separate program that takes in a single argument and prints that many items from the Fibonacci sequence. You main program should ask for a number from the user and then launch the other program by passing in this number as an argument.
The question says to spawn a process that outputs a Fibonacci sequence. Get/validate the user input in the main process, then spawn another program (written separately) to print the Fibonacci sequence. Pass the user input to the spawned process as a command-line parameter.
Related
I found this Redirect ouput to another instance terminal window post and tried to play with similar code alternatives, but got unexpected results when using the sleep function, or similar, in conjunction with the fork function.
I run the code below from a ("parent") terminal window. The program is supposed to open another (child) terminal window and print some text to both the parent and child terminals in an infinite loop.
The issue is that the frequency of the printing in each window is not the same, in fact it can be very different.
I tried 4 alternative loops (one need to comment out only 1 of the 4 alternatives at the same time). The alternative-1 is too fast to see much and the printing frequencies look similar in both windows.
The issues arise when I try to slow down the loop, either with the sleep function or a long secondary loop (*), in the alternatives-2, -3 and -4. There, one can see that the timing of text outputs becomes out of sync between the 2 terminals and, while the messages (seem to) print with the desired periodicity in the parent window, e.g. with 1 second delay with sleep(1), the periodicity in the child window seems random and lagging (eg on my machine it takes ~200 seconds before the first output in the child window). Alternative-4 is similar to alternative-2, but with fwrite instead of fprintf.
My questions : why such a lag between the two windows? Is this lag "deterministic" or random? What would be the way to make both terminals print at the same, regular, frequency?
I'm on Linux. gcc logwindow.c -o logwindow should be enough to compile the code.
(*) I am aware that using a long loop (in alternative-3) instead of the sleep function is bad practice. I just tried to see if it would give different results from the sleep function.
#include <stdlib.h> // system
#include <stdio.h> // tempnam, sprintf
#include <unistd.h> // sleep
#include <sys/types.h> // pid_t
FILE *logwindow(){
char *fp = tmpnam(NULL); //generate a random filepath/name
char cmd[256];
pid_t pid;
mkfifo(fp, 0777);
pid = fork();
if (pid==0) {
sprintf(cmd, "xterm -e \"cat %s\"", fp);
system(cmd);
return(NULL);
}
return fopen(fp, "w");
}
int main(){
FILE *log = logwindow();
if (log == NULL) {
printf("child process, exiting\n");
exit(0);
}
else {
printf("parent process, keep going\n");
int i=0;
/* comment out only 1 alternative out of the 4 */
// alternative-1
for(;;){
fprintf(log, "i=%d, Child Terminal here\n", i); // print to child terminal
printf("i=%d, Parent Terminal here\n", i); // print to parent terminal
i++;
}
// alternative-2
/*
for(;;){
fprintf(log, "i=%d, Child Terminal here\n", i); // print to child terminal
printf("i=%d, Parent Terminal here\n", i); // print to parent terminal
sleep(1);
i++;
}
*/
// alternative-3
/*
int j=0;
for(i=0;i<100000;i++){
fprintf(log, "i=%d, Child Terminal here\n", i); // print to child terminal
printf("i=%d, Parent Terminal here\n", i); // print to parent terminal
for(j=0;j<5000000;j++){} // simulate the sleep function
}
*/
// alternative-4
/*
char alt4text[] = "Child Terminal here\n";
for(;;){
fwrite(alt4text, 1, sizeof(alt4text),log); // print to child terminal
printf("i=%d, Parent Terminal here\n", i); // print to parent terminal
sleep(1);
i++;
}
*/
}
}
You are probably having issues with buffering.
Try calling fflush() after a call to fprintf()
fprintf(log, "i=%d, Child Terminal here\n", i); // print to child terminal
fflush(log)
Alternatively you could look into line buffering or disabling buffering entirely by using setbuf() / setvbuf()
Note also that for(j=0;j<5000000;j++){} is not a good idea - ever. This is referred to as a "busy loop", and will hog processor time - increasing power usage, temperatures, and starving other processes of resources.
This is a bad idea even if you are working on a microcontroller and should be avoided wherever possible.
Additionally, depending on compiler optimisation settings, this may produce no instructions at all, silently making alternative-3 equivalent to alternative-1.
I am having an issue with some code for an assignment to familiarize myself with processes and the fork() system call. For some reason when I call scanf() in the initial if statement it isn't waiting for an input right away, first the program proceeds to the next scanf and waits for input there. I know there are many similar quests but I couldn't find one with my exact problem.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(){
pid_t pid;
int pipeid[2];
pid = fork();
if(pid >0){
int x;
printf("reading x from user: ");
scanf("%d", &x);
printf("display %d",x);
wait(0);
}
else{
int y;
printf("reading y from user: ");
scanf(" %d", &y);
printf("%d",y);
printf("parent proccess %d created child proccess %d\n", getppid(),getpid());
}
}
output for this program looks like this
reading x from user: reading y from user 3
4
4parentproccess (Ppid) created child process (pid)
display 3
the first 3 and 4 are user input, so it seems like the program is going straight to the second scanf after it sees the first one? The process ids are always correct.
You're forking the process before calling scanf. This gives you 2 processes. Both processes are then calling scanf, one reading "x" and the other reading "y". They're both waiting for user input, but because you have two processes both doing it at the same time, you get both messages.
I need to create a program that takes input from the user and executes it just like it does in the terminal. I am using the execvp() function for this purpose. The requirement of the program is to keep taking input from the user unless the quit call is encountered. The problem here is that the current program is replaced after the execvp() call. So, using a goto is not an option either. I found this Fork–exec article but it doesn't tell how to create an indefinite number of processes. Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void main() {
char *args[4];
char inputCommand[100];
fgets (inputCommand, 100, stdin);
printf ("Splitting string \"%s\" into tokens:\n",inputCommand);
/* Perfrom string tokenization here */
execvp(args[0], args);
}
fork() can be called an indefinite number of times; as long as the return value indicates that you're the parent process, you can continue to operate as usual and call it again.
Thus, you can have a loop within which you fork, call an execvp() if you're the child process, and continue to the next iteration if you're the parent.
Execvp replaces the current process image with the command you run. So it cancels your C program. To produce the desired effect, you should fork before execvp. It would look something like this:
int status = 0;
pid_t pid = fork();
if(pid > 0) {
waitpid(pid, &status, 0);
// is parent
} else if(pid == 0) {
execvp(*args, args);
// is child
} else {
// fork didn't work
}
I'm doing a small c program for testing some Unix commands.
I provide the user with choices he can test and then allows him to enter his choice. If the user enters the number 2 as his choice ,the following code should run which is testing the grep command on a file. But there is something wrong with the code
when I enter the "pattern", it starts an infinite loop ,
Any help ?!! I don't have much experience in Unix progamming.
the problem appears when I enter the number 2 as my choice ,means that it's in case no.2
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(){
char pattern[50];
int userInput;
pid_t childPID;
char filename[50];
FILE *file;
printf("Enter a File name:");
scanf("%s",filename);
file = fopen(filename, "r");
do{
printf("Enter what u want to do with the file:\n");
printf("1.Compress the file.\n");
printf("2.Search for a pattern at the file\n");
printf("3.Read the file (display the file content at the terminal)\n");
printf("4.Eject the program\n");
scanf("%d",&userInput);
switch(userInput){
case 1:
if(childPID == 0){
execl("/bin/gzip","gzip",filename,NULL);
exit(1);
}
break;
case 2: childPID = fork();
if(childPID ==0){
printf("Enter the pattern you want to search about:");
scanf("%s",pattern);
execl("/bin/grep","grep",pattern,filename,NULL);
}
break;
}
}while(userInput != 4);
return 0;
}
The execlp() or exec() family of functions replaces the current process image with a new process image so when execlp() exits then child terminates but fork() returns some non-zero value to parent process.
The main point is after doing fork() there are two independent processes
1st : main process called parent
2nd : child process
And you can't control their execution order it's unspecified. so put wait(NULL) in you parent code just after the child code finishes.
So that parent will wait till child terminates. otherwise both independent processes will run in this way. Sometimes you find that only parent is running (that's infinite loop) but sometimes you see that child is running too.
The only reason I see this could get into an infinite loop is when execl() fails. Print errno after execl() to see what's going wrong.
...
execl("/bin/grep","grep",pattern,filename,NULL);
printf("errno=%d\n", errno);
}
break;
I am having some trouble understanding the following simple C code:
int main(int argc, char *argv[]) {
int n=0;
fork();
n++;
printf("hello: %d\n", n);
}
My current understanding of a fork is that from that line of code on, it will split the rest of the code in 2, that will run in parallel until there is "no more code" to execute.
From that prism, the code after the fork would be:
a)
n++; //sets n = 1
printf("hello: %d\n", n); //prints "hello: 1"
b)
n++; //sets n = 2
printf("hello: %d\n", n); //prints "hello: 2"
What happens, though, is that both print
hello: 1
Why is that?
EDIT: Only now it ocurred to me that contrary to threads, processes don't share the same memory. Is that right? If yes, then that'd be the reason.
After fork() you have two processes, each with its own "n" variable.
fork() starts a new process, sharing no variables/memory locations.
It is very similar to what happens if you execute ./yourprogram twice in a shell, assuming the first thing the program does is forking.
At fork() call's end, both the processes might be referring to the same copy of n. But at n++, each gets its own copy with n=0. At the end of n++; n becomes 1 in both the processes. The printf statement outputs this value.
Actually you spawn a new process of the same progarm. It is not the closure kind of thing. You could use pipes to exchange data between parent and child.
You did indeed answer your own question in your edit.
examine this code and everything should be clearer (see the man pages if you don't know what a certain function does):
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int count = 1;
int main(int argc, char *argv[]) {
// set the "startvalue" to create the random numbers
srand(time(NULL));
int pid;
// as long as count is <= 50
for (count; count<=50; count++) {
// create new proccess if count == 9
if (count==9) {
pid = fork();
// reset start value for generating the random numbers
srand(time(NULL)+pid);
}
if (count<=25) {
// sleep for 300 ms
usleep(3*100000);
} else {
// create a random number between 1 and 5
int r = ( rand() % 5 ) + 1;
// sleep for r ms
usleep(r*100000);
}
if (pid==0) {
printf("Child: count:%d pid:%d\n", count, pid);
} else if (pid>0) {
printf("Father: count:%d pid:%d\n", count, pid);
}
}
return 0;
}
happy coding ;-)
The system call forks more than the execution thread: also forked is the data space. You have two n variables at that point.
There are a few interesting things that follow from all this:
A program that fork()s must consider unwritten output buffers. They can be flushed before the fork, or cleared after the fork, or the program can _exit() instead of exit() to at least avoid automatic buffer flushing on exit.
Fork is often implemented with copy-on-write in order to avoid unnecessarily duplicating a large data memory that won't be used in the child.
Finally, an alternate call vfork() has been revived in most current Unix versions, after vanishing for a period of time following its introduction i 4.0BSD. Vfork() does not pretend to duplicate the data space, and so the implementation can be even faster than a copy-on-write fork(). (Its implementation in Linux may be due less to speed reasons than because a few programs actually depend on the vfork() semantics.)