Avatar of kinsey
kinsey

asked on 

Visual C++ Timer ala Unix signal(), alarm()

How does the C++ SetTimer() function without a wndow?
I need to set a timeout on user input to getchar() using Visual C++ 6.0
I'm looking for something equivilent to the Unix signal() and alarm() functions.
The only thing I can find in the docs are SetTimer)( and KillTimer() wich sound like they would work but don't seem to do anything.

Here is the code I have tried. It just reaches the getchar() and sits there, never timing out.
...
VOID CALLBACK TimerProc(  HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{      printf("Time Out");
      exit(-2);
}

int main(int argc, char* argv[], char* env[])
{
 HWND hWnd;
 UINT_PTR nIDEvent;
 UINT uElapse;
 TIMERPROC lpTimerFunc;
 hWnd=NULL;
 nIDEvent=NULL;
 uElapse=1000;
 lpTimerFunc = (TIMERPROC) TimerProc;
 nIDEvent=SetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc );
 getchar();
 exit(0);
}
System ProgrammingC++

Avatar of undefined
Last Comment
itsmeandnobodyelse
Avatar of jkr
jkr
Flag of Germany image

>>How does the C++ SetTimer() function without a wndow?

Theoretically, that should work. The catch is that even if you specify a 'TimerProc()', your app will still need a message loop in order for 'SetTimer()' to work (there used to be a MSDN article that stated "SetTimer() was not designed to be used with a console application because it requires a message loop to dispatch the timer signal to the timer procedure. In a console application, this behavior can be easily emulated with a thread that is set to wait on an event.". The options now are to either create a thread that periodically triggers the code that you want to be executed periodically or use 'CreateWaitableTimer()' instead. For the latter, see http://support.microsoft.com/kb/184796 ("How To Use a Waitable Timer with an Asynchronous Procedure Call"). I''ll attach code snippets for both options
// thread
 
#include <windows.h>
#ibclude <stdio.h>
 
DWORD WINAPI My30SecWaitThread ( LPVOID) {
// do something after 30mins
 
  Sleep ( 30 * 1000);
  printf("Time Out");
}
 
void main () {
 
  DWORD dwTID;
 
  CreateThread(NULL,0,My30SecWaitThread, 0, 0, &dwTID);
 
  Sleep(60 * 1000);
 
}
 
// waitable timer
 
   #define _WIN32_WINNT 0x0400
   #include <windows.h>
   #include <stdio.h>
 
   #define _SECOND 10000000
 
   typedef struct _MYDATA {
     TCHAR *szText;
     DWORD dwValue;
   } MYDATA;
 
 
   VOID CALLBACK TimerAPCProc(
       LPVOID lpArg,               // Data value.
       DWORD dwTimerLowValue,      // Timer low value.
       DWORD dwTimerHighValue ) {  // Timer high value.
 
     MYDATA *pMyData = (MYDATA *)lpArg;
 
     printf( "Message: %s\nValue: %d\n\n", pMyData->szText,
       pMyData->dwValue );
     MessageBeep(0);
 
   }
 
 
   void main( void ) {
 
     HANDLE          hTimer;
     BOOL            bSuccess;
     __int64         qwDueTime;
     LARGE_INTEGER   liDueTime;
     MYDATA          MyData;
     TCHAR           szError[255];
 
     MyData.szText = "This is my data.";
     MyData.dwValue = 100;
 
     if ( hTimer = CreateWaitableTimer(
           NULL,                   // Default security attributes.
           FALSE,                  // Create auto-reset timer.
           "MyTimer" ) ) {         // Name of waitable timer.
 
       __try {
 
         // Create a negative 64-bit integer that will be used to
         // signal the timer 5 seconds from now.
         qwDueTime = -5 * _SECOND;
 
         // Copy the relative time into a LARGE_INTEGER.
         liDueTime.LowPart  = (DWORD) ( qwDueTime & 0xFFFFFFFF );
         liDueTime.HighPart = (LONG)  ( qwDueTime >> 32 );
 
 
         bSuccess = SetWaitableTimer(
           hTimer,                 // Handle to the timer object.
           &liDueTime,             // When timer will become signaled.
           2000,                   // Periodic timer interval of 2 seconds.
           TimerAPCProc,           // Completion routine.
           &MyData,                // Argument to the completion routine.
           FALSE );                // Do not restore a suspended system.
 
         if ( bSuccess ) {
 
           for ( ; MyData.dwValue < 1000; MyData.dwValue += 100 ) {
 
             SleepEx(
               INFINITE,           // Wait forever.
               TRUE );             // IMPORTANT!!! The thread must be in an
                                   // alertable state to process the APC.
           }
 
         } else {
           wsprintf( szError, "SetWaitableTimer() failed with Error %d.",
             GetLastError() );
           MessageBox( NULL, szError, "Error", MB_ICONEXCLAMATION );
         }
 
       } __finally {
         CloseHandle( hTimer );
       }
 
     } else {
       wsprintf( szError, "CreateWaitableTimer() failed with Error %d.",
         GetLastError() );
       MessageBox( NULL, szError, "Error", MB_ICONEXCLAMATION );
     }
 
   }

Open in new window

Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> I need to set a timeout on user input to getchar() using Visual C++ 6.0
Even if you can set a timer how do you plan to make the getchar() call end?
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

See if this helps...

A timed input function using _kbhit() and _getch() both of which are Microsoft extensions to standard C++ (so this code is non-portable).

http://msdn.microsoft.com/en-us/library/58w7c94c(VS.80).aspx
http://msdn.microsoft.com/en-us/library/078sfkak(VS.80).aspx
#include <conio.h>
#include <time.h>
#include <string>
#include <iostream>
 
std::string timout_input(unsigned int secs)
{
	std::string s;
	time_t t1 = time(NULL) + secs;
 
	while(t1 > time(NULL))
	{
		if(_kbhit())
		{
			char c = static_cast<char>(_getch());
			if('\r' == c || '\n' == c) {
				std::cout << std::endl;
				break;
			}
			std::cout << c;
			s += c;
		}
	}
 
	return s;
}
 
int main( void )
{
	std::string const & s = timout_input(5);
 
	std::cout
		<< "You entered: "
		<< s
		<< std::endl;
}

Open in new window

Avatar of kinsey
kinsey

ASKER

evilrix:
"Even if you can set a timer how do you plan to make the getchar() call end?"
That's what the timer is for.
if it times out the callback would do clean up and abort the application.
evilrix:(2)
 timout_input(unsigned int secs)  could work in a normal console app but  timout_input(unsigned int secs) would loop consuming CPU and ther could be several of these runing.

It is not realy a console aapplication. stdin is a telnet session from a remote terminal using cygwin as the telnet server.

jkr: I'll look further at
CreateWaitableTimer
Avatar of jkr
jkr
Flag of Germany image

>>jkr: I'll look further at
>>CreateWaitableTimer

I'd first check if the thread solution isn't easier for you.
Avatar of kinsey
kinsey

ASKER

jkr:
Currently I'm single threaded and it's been a long-long time since I tried usng threads.
Where I want to get is something like:
while true {
settimer( 30 min, callback_proc);
getchar();
killtimer();
process keystroke
}
and the callback_proc simply closes some files and exits the application.

The real problem here is that the progran executes accross a WAN and sometimes the connection gets lost. When that happens the application runs forever waiting for input and needs to be killed. I want it to exit gracefully.

if I user the thread method how do I clear (reset)  the tiimer?
Thanks, I'll give it a try.
Avatar of jkr
jkr
Flag of Germany image

>>Currently I'm single threaded and it's been a long-long time since I tried usng
>>threads.

It is actually as simple as outlined above, no other complexities involved. You can just
#include <windows.h>
#ibclude <stdio.h>
 
DWORD WINAPI My30SecWaitThread ( LPVOID) {
 
// timeout after 30secs
 
  Sleep ( 30 * 1000);
  printf("Time Out");
 
  ExitProcess(0);
 
  return 0;
}
 
void main () {
 
  DWORD dwTID;
 
  CreateThread(NULL,0,My30SecWaitThread, 0, 0, &dwTID);
 
  getchar();
 
}

Open in new window

Avatar of kinsey
kinsey

ASKER

jkr:
...but when getchar()  _DOES_ return I want to rest the timer.....?
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> would loop consuming CPU and ther could be several of these runing.
Put a ::Sleep(0) in the loop and it will yield allowing all other threads/processes a quantum.
Avatar of jkr
jkr
Flag of Germany image

>>.but when getchar()  _DOES_ return I want to rest the timer.....?

Sorry, I forgot:
#include <windows.h>
#ibclude <stdio.h>
 
DWORD WINAPI My30SecWaitThread ( LPVOID) {
 
// timeout after 30secs
 
  Sleep ( 30 * 1000);
  printf("Time Out");
 
  ExitProcess(0);
 
  return 0;
}
 
void main () {
 
  DWORD dwTID;
 
  HANDLE hThread = CreateThread(NULL,0,My30SecWaitThread, 0, 0, &dwTID);
 
  getchar();
 
  TerminateThread(hThread,0); // cancel thread
 
}

Open in new window

Avatar of kinsey
kinsey

ASKER

Thanks!!!

Thats what I need!
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Isn't there a problem with this though? Just because the user hasn't hit enter doesn't mean they aren't actively typing. They might be int he middle of entering data, slowly (for what ever reason) and then you just terminate the app because they haven't hit enter. Are you sure this is really what you want to do?
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> Isn't there a problem with this though? Just because the user hasn't hit enter doesn't mean they aren't actively typing
This will reset the timeout after every keypress... the Sleep() will yield after each loop, preventing CPU hogging. If what you have already works for you then that's fine, if not then this might.
#include <conio.h>
#include <time.h>
#include <string>
#include <iostream>
#include <windows.h>
 
std::string timout_input(unsigned int secs)
{
	std::string s;
	time_t t1 = time(NULL) + secs;
 
	while(t1 > time(NULL))
	{
		if(_kbhit())
		{
			char c = static_cast<char>(_getch());
			if('\r' == c || '\n' == c) {
				std::cout << std::endl;
				break;
			}
			std::cout << c;
			s += c;
 
			t1 = time(NULL) + secs; // Reset timeout
		}
 
		Sleep(0); // Yield (give other threads/processes a chance)
	}
 
	return s;
}
 
int main( void )
{
	std::string const & s = timout_input(5);
 
	std::cout
		<< "You entered: "
		<< s
		<< std::endl;
}

Open in new window

Avatar of kinsey
kinsey

ASKER

jkr:
I still have a problem..
The following code compiles and runs but  does not time out..?
Any Idea?

evilrix: I process each key stroke, not just enters. If someone does not hit a key for 20-30 minuites or more I'll assume they are gone.


#include <windows.h>
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>
#include <process.h>
#include "stdafx.h"
#include <afx.h>
#include <string.h>
#include <stdio.h>
#include <afxdb.h>
 
DWORD WINAPI WaitThread ( LPVOID ) {
// do something after 30mins
  //Sleep ( 30 *  60 * 1000);
  Sleep (100);
  printf("Time Out");
  fflush(stdout);
  ExitProcess(0);
  return 0;
}
 
int main(int argc, char* argv[], char* env[])
{
HANDLE hThread;
DWORD dwTID;
int i;
while (true) {
	i=getchar();
	hThread = CreateThread( NULL,0, WaitThread, 0, 0, &dwTID);// cancel thread
	printf("T: %x \n",hThread);
	fflush(stdout);
	putchar(i);
	TerminateThread(hThread,0); // cancel thread
}
	return 0;
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
Avatar of jkr
jkr
Flag of Germany image

BTW, one other thing 'Sleep(100);' only sleeps for 0.1s, that's a bit tight ;o)
Avatar of kinsey
kinsey

ASKER

my bad...

This now works
while (true) {
	hThread = CreateThread( NULL,0, WaitThread, 0, 0, &dwTID);// cancel thread
	Sleep(0);
	i=getchar();
	printf("T: %x \n",hThread);
	fflush(stdout);
	putchar(i);
	TerminateThread(hThread,0); // cancel thread
}

Open in new window

Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> I process each key stroke, not just enters. If someone does not hit a key for 20-30 minuites or more I'll assume they are gone.
But getchar only returns once enter is pressed, so how do you achieve that? How to you register when a key is being pressed?
http://www.cplusplus.com/reference/clibrary/cstdio/getchar.html
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> But getchar only returns once enter is pressed
I tried your code, below, and as I suspected it just aborts even when I am typing (as long as I don't press enter).
#include <windows.h>
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>
#include <process.h>
#include "stdafx.h"
//#include <afx.h>
#include <string.h>
#include <stdio.h>
//#include <afxdb.h>
 
DWORD WINAPI WaitThread ( LPVOID ) {
	// do something after 30mins
	//Sleep ( 30 *  60 * 1000);
	Sleep (5sd000);
	printf("Time Out");
	fflush(stdout);
	ExitProcess(0);
	return 0;
}
 
int main(int argc, char* argv[], char* env[])
{
	HANDLE hThread;
	DWORD dwTID;
	int i;
	while (true) {
		hThread = CreateThread( NULL,0, WaitThread, 0, 0, &dwTID);// cancel thread
		Sleep(0);
		i=getchar();
		printf("T: %x \n",hThread);
		fflush(stdout);
		putchar(i);
		TerminateThread(hThread,0); // cancel thread
	}
	return 0;
}

Open in new window

Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> as I suspected it just aborts even when I am typing
NB. Try using _getch() instead of getchar and it should work as you want.
Avatar of kinsey
kinsey

ASKER

evilrix:
you are correct that a standar console task blocks on getchar() until ENTER has been pressed.
This is because sometime Microsoft acts brain dead.
In my case stdin is _NOT_ the console. _getch() reads directly from the keyboard device and can not be used here. Stdin is comming from another process (in.telnetd) that intern ins connected to a network socket. I had to use the Cygwin telnetd daemon because the Microsoft one is also brain dead and assumes a Windows Console at the remote end and will not work in character mode.

The code below works for me. I did have to add the two Sleep(10) calls to make it work.
Without them thprogram seems to function if the user does not type too fast. When the user does type fast it continues in the loop echoing charaters but does not timeout when the user stops typing.
I'm not sure why. Seems to be some race condition calling CreateThread/TerminateThread too rapidly.
Task manager always shows the process withe 2 threads and the programs is reponding so I do not understand what is happening.

I added the if (i== 0x3) return(0); to allow ^C to terminate the process, but even then it the user types a number of characters rapidly then stops there is no timeout. then if the user hits ^C the program hangs and stops echoing. I have to kill the process. With the Sleeps It seems to work. I hate using timers to beat a race condition because there is allways the chance that a faster or slower CPU will break the program.





#include <windows.h>
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>
#include <process.h>
#include "stdafx.h"
#include <afx.h>
#include <string.h>
#include <stdio.h>
#include <afxdb.h>
 
long lTimeout;
 
DWORD WINAPI WaitThread ( LPVOID ) {
// do something after 30mins
  //Sleep ( 30 *  60 * 1000);
  Sleep (lTimeout);
  printf("Time Out"); fflush(stdout);
  ExitProcess(0);
  return 0;
}
 
int main(int argc, char* argv[], char* env[])
{
HANDLE hThread;
DWORD dwTID;
int i;
lTimeout=1000;
if (argc >1) lTimeout = atol(argv[1]);
printf("Timeout %d\n",lTimeout);fflush(stdout);
while (true) {
	hThread = CreateThread( NULL,0, WaitThread, 0, 0, &dwTID);// cancel thread
	Sleep(10);
	i=(getchar)() ;
	putchar(i);
	if (i== 0x3) return(0);
	fflush(stdout);
	TerminateThread(hThread,0); // cancel thread
	Sleep(10);
}
	return 0;
}

Open in new window

Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> I hate using timers to beat a race condition because there is allways the chance that a faster or slower CPU will break the program.
Try this, see if it resolves your race condition problem.
#include <windows.h>
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>
#include <process.h>
#include "stdafx.h"
//#include <afx.h>
#include <string.h>
#include <stdio.h>
//#include <afxdb.h>
 
long lTimeout = 1000;
HANDLE hEvent = CreateEvent(NULL, true, false, NULL);
 
DWORD WINAPI WaitThread ( LPVOID )
{
	SetEvent(hEvent);
	Sleep(lTimeout);
	printf("Time Out"); fflush(stdout);
	ExitProcess(0);
 
	return 0;
}
 
int main(int argc, char* argv[], char* env[])
{
	if(argc >1) { lTimeout = atol(argv[1]); }
 
	printf("Timeout %d\n",lTimeout);fflush(stdout);
 
	for(;;)
	{
		HANDLE hThread = CreateThread( NULL,0, WaitThread, 0, 0, 0);
		WaitForSingleObject(hEvent, INFINITE);
		int i = getchar();
		TerminateThread(hThread,0); 
		putchar(i);
		if (i== 0x3) return(0);
		fflush(stdout);
	}
 
	return 0;
}

Open in new window

SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
>>>> I've changed the code to get rid of ThreadTerminate (it's a nasty way to stop a thread).

Indeed. But ExitProcess called in a thread isn't much better.

You should test for user input with _kbhit as evilrix suggested above. That wouldn't block and you easily could poll with little intervals using Sleep to let other processes gain some CPU time also.  That doesn't need a tread and is clean and simple.
Avatar of kinsey
kinsey

ASKER

If you read the thread you will see why _kbhit() is no good.
stdin is NOT the Keyboard, another process is.

How else would you terminate a getchar() waiting in another thread?

evilrix's solution works great and solves the problem.
Now using it in a multi-user enviroment with no issues so far.


Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> Indeed. But ExitProcess called in a thread isn't much better.
Agreed. I was just trying to make it a little better. :)
>>>> How else would you terminate a getchar() waiting in another thread?
I wouldn't call the getchar() because of that but call peek() to not block. peek goes for the stdin same as getchar().

>>>>evilrix's solution works great and solves the problem.
Good. I am a fan of pragmatical solutions.

But when using TerminateThread or ExitProcess the resources bound in the other threads were not freed (it may depend on the Windows version and/or on the kind of resources). If your program is the only application that wa running or if it runs only once a day you may not care, but if your prog is one of many programs or was invoked a hundred times every day, you should use techniques which make a smooth shutdown by not killing threads but gently give them time to terminate.
C++
C++

C++ is an intermediate-level general-purpose programming language, not to be confused with C or C#. It was developed as a set of extensions to the C programming language to improve type-safety and add support for automatic resource management, object-orientation, generic programming, and exception handling, among other features.

58K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo