I guess I wasn't clear; I don't want the program to be doing nothing
while waiting for an "enter" from the KB. My program may be running for
hours, doing simulated evolution. I need to occaisonally give it some
data, or make a decision for it. I don't mind if it pauses while
interacting with me, but after that it must continue processing.
Is there a way of doing that with the standard input stream?
Not directly, but if you have a reliable way of generating SIGINT
(ctrl-C should do this on both Unix and Windows), you can fake it.
You'll need a flag that the signal handler will set to indicate that
the user wants to talk to the program:
--------
#include <signal.h>
volatile sig_atomic_t stop_and_get_input;
--------
You'll need a signal handler that looks something like this:
--------
#include <signal.h>
void sigint_handler(int sig)
{
stop_and_get_input=1;
/*Reinstate the signal handler. May or may not be required
(N869 7.14.1.1#3), but causes no problems if done when not
required (N869 7.14.1.1#5).
*/
#ifdef PARANOID
/*Set failed_to_reinstate_handler (which should be a volatile
sig_atomic_t) to indicate that something went wrong and we
won't be able to request an interactive session again
*/
if(signal(sig,sigint_handler) == SIG_ERR)
failed_to_reinstate_handler=1;
#else /*Not paranoid, so just assume reinstatement succeeded*/
signal(sig,sigint_handler);
#endif
}
--------
Before you enter your main loop, install the signal handler like this:
--------
/*Near the beginning of main is probably the best place to put this.
Don't forget to #include <signal.h>.
*/
void (*oldsigfunc)(int);
oldsigfunc=signal(SIGTERM,sigint_handler);
if(oldsigfunc == SIG_ERR)
{
fputs("Can't install signal handler - user interaction requests are unavailable\n",stderr);
}
else if(oldsigfunc == SIG_IGN)
{
fputs("SIGTERM was ignored (perhaps we're running in the background?), re-ignoring\n",stderr);
signal(SIGTERM,SIG_IGN);
}
--------
Now when your program fgets the SIGINT signal (usually as a result
of getting a ctrl-C at the keyboard), the signal handler will run and
set stop_and_get_input to indicate that this happened, so now you can
put something like this inside your main loop:
--------
/*This should go somewhere deep enough in the main loop to run within
a reasonable amount of time after the signal handler runs, but not
deep enough to slow down the program by running millions of times
a second or to run in the middle of something that you don't want
to be changing parameters in the middle of.
*/
if(stop_and_get_input)
{
do_user_input();
stop_and_get_input=0;
}
--------
The program won't run in the background while do_user_input() is running,
so you'll need to have a way for the user to tell it "OK, I'm done, go
back to crunching and I'll interrupt you again if I have more to say".
It would also be nice for it to have a way to exit the program without
running to completion, since the usual response to SIGINT is for the
program to do that (without stopping and bothering the user first).
One thing that may not work, and is a Bad Idea anyways, is to have the
signal handler call do_user_input directly. Since standard C doesn't
require that you be able to call library functions from a signal handler
(with a few exceptions, like reinstating the signal handler or installing
a new one for the same signal), you can't do this without invoking
undefined behavior; also, at least one rather common system (Windows)
will run the signal handler in its own thread while the main program
continues to run, forcing you to deal with concurrency issues if you
change anything that the program wants to be able to use.
dave
--
Dave Vandervies (e-mail address removed)
May I be excused for showing incomplete/incorrect knowledge of C++ knowledge
in a C newsgroup? --Michael Rubenstein and Ian Woods in comp.lang.c