|
|
我写了一个程序,希望用户从键盘输入一个字符[getchar()],如果5秒钟过去了,用户仍未输入字符,则继续执行getchar()后的代码,但我的程序却始终在等待键盘输入,如没有输入,则无法执行到后面的代码,请各位大佬看看问题出在哪里?
请不吝赐教!!!
我的程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#define TIMEOUT 5
void sigProcess(int);
main(void)
{
printf("The program is about to get a character from the keyboard:\n");
alarm(TIMEOUT);
signal(SIGALRM,sigProcess);
getchar();
........... /* here goes the code if timeout */
}
void sigProcess(int signo)
{
signal(SIGALRM,SIG_DFL);
printf("In the signal process function: TIMEOUT\n");
}
| Alligator27 回复于:2005-04-09 01:25:48
| getchar()是blocking函数. 你要non-blocking函数.
window: kbhit()
unix: 这个函数simulator
http://www.pwilson.net/kbhit.html
/* ***************************************************************************
*
* Copyright 1992-2005 by Pete Wilson All Rights Reserved
* 50 Staples Street : Lowell Massachusetts 01851 : USA
* http://www.pwilson.net/ pete@pwilson.net +1 978-454-4547
*
* This item is free software: you can redistribute it and/or modify it as
* long as you preserve this copyright notice. Pete Wilson prepared this item
* hoping it might be useful, but it has NO WARRANTY WHATEVER, not even any
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*************************************************************************** */
/* ***************************************************************************
*
* KBHIT.C
*
* Based on the work of W. Richard Stevens in "Advanced Programming in
* the Unix Environment," Addison-Wesley; and of Floyd Davidson.
*
* Contains these functions:
*
* To set the TTY mode:
* tty_set_raw() Unix setup to read a character at a time.
* tty_set_cooked() Unix setup to reverse tty_set_raw()
*
* To read keyboard input:
* kb_getc() keyboard get character, NON-BLOCKING. If a char
* has been typed, return it. Else return 0.
* kb_getc_w() kb get char with wait: BLOCKING. Wait for a char
* to be typed and return it.
*
* How to use:
* tty_set_raw() set the TTY mode to read one char at a time.
* kb_getc() read chars one by one.
* tty_set_cooked() VERY IMPORTANT: restore cooked mode when done.
*
* Revision History:
*
* DATE DESCRIPTION
* ----------- --------------------------------------------
* 12-jan-2002 new
* 20-aug-2002 cleanup
*
* Notes:
* ----------- --------------------------------------------
* 25-nov-2003 notate anomoly in some Unices: termattr.c_cc[VMIN] = 0;
*************************************************************************** */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
extern int errno;
static struct termios termattr, save_termattr;
static int ttysavefd = -1;
static enum
{
RESET, RAW, CBREAK
} ttystate = RESET;
/* ***************************************************************************
*
* set_tty_raw(), put the user's TTY in one-character-at-a-time mode.
* returns 0 on success, -1 on failure.
*
*************************************************************************** */
int
set_tty_raw(void)
{
int i;
i = tcgetattr (STDIN_FILENO, &termattr);
if (i < 0)
{
printf("tcgetattr() returned %d for fildes=%d\n",i,STDIN_FILENO);
perror ("");
return -1;
}
save_termattr = termattr;
termattr.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
termattr.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
termattr.c_cflag &= ~(CSIZE | PARENB);
termattr.c_cflag |= CS8;
termattr.c_oflag &= ~(OPOST);
termattr.c_cc[VMIN] = 1; /* or 0 for some Unices; see note 1 */
termattr.c_cc[VTIME] = 0;
i = tcsetattr (STDIN_FILENO, TCSANOW, &termattr);
if (i < 0)
{
printf("tcsetattr() returned %d for fildes=%d\n",i,STDIN_FILENO);
perror("");
return -1;
}
ttystate = RAW;
ttysavefd = STDIN_FILENO;
return 0;
}
/* ***************************************************************************
*
* set_tty_cbreak(), put the user's TTY in cbreak mode.
* returns 0 on success, -1 on failure.
*
*************************************************************************** */
int
set_tty_cbreak()
{
int i;
i = tcgetattr (STDIN_FILENO, &termattr);
if (i < 0)
{
printf("tcgetattr() returned %d for fildes=%d\n",i,STDIN_FILENO);
perror ("");
return -1;
}
save_termattr = termattr;
termattr.c_lflag &= ~(ECHO | ICANON);
termattr.c_cc[VMIN] = 1;
termattr.c_cc[VTIME] = 0;
i = tcsetattr (STDIN_FILENO, TCSANOW, &termattr);
if (i < 0)
{
printf("tcsetattr() returned %d for fildes=%d\n",i,STDIN_FILENO);
perror ("");
return -1;
}
ttystate = CBREAK;
ttysavefd = STDIN_FILENO;
return 0;
}
/* ***************************************************************************
*
* set_tty_cooked(), restore normal TTY mode. Very important to call
* the function before exiting else the TTY won't be too usable.
* returns 0 on success, -1 on failure.
*
*************************************************************************** */
int
set_tty_cooked()
{
int i;
if (ttystate != CBREAK && ttystate != RAW)
{
return 0;
}
i = tcsetattr (STDIN_FILENO, TCSAFLUSH, &save_termattr);
if (i < 0)
{
return -1;
}
ttystate = RESET;
return 0;
}
/* ***************************************************************************
*
* kb_getc(), if there's a typed character waiting to be read,
* return it; else return 0.
*
*************************************************************************** */
unsigned char
kb_getc(void)
{
unsigned char ch;
ssize_t size;
size = read (STDIN_FILENO, &ch, 1);
if (size == 0)
{
return 0;
}
else
{
return ch;
}
}
/* ***************************************************************************
*
* kb_getc_w(), wait for a character to be typed and return it.
*
*************************************************************************** */
unsigned char
kb_getc_w(void)
{
unsigned char ch;
size_t size;
while (1)
{
usleep(20000); /* 1/50th second: thanks, Floyd! */
size = read (STDIN_FILENO, &ch, 1);
if (size > 0)
{
break;
}
}
return ch;
}
#define TEST
#ifdef TEST
void echo(unsigned char ch);
static enum
{
CH_ONLY, CH_HEX
} how_echo = CH_ONLY;
int
main(int argc, char * argv[])
{
unsigned char ch;
printf("Test Unix single-character input.\n");
set_tty_raw(); /* set up character-at-a-time */
while (1) /* wait here for a typed char */
{
usleep(20000); /* 1/50th second: thanks, Floyd! */
ch = kb_getc(); /* char typed by user? */
if (0x03 == ch) /* might be control-C */
{
set_tty_cooked(); /* control-C, restore normal TTY mode */
return 1; /* and get out */
}
echo(ch); /* not control-C, echo it */
}
}
void
echo(unsigned char ch)
{
switch (how_echo)
{
case CH_HEX:
printf("%c,0x%x ",ch,ch);
break;
default:
case CH_ONLY:
printf("%c", ch);
break;
}
fflush(stdout); /* push it out */
}
#endif /* test */
#ifdef __cplusplus
}
#endif
/* ----- Notes -----
1. Some flavors of Unix need termattr.c_cc[VMIN] = 0 here else the read() in kb_getc() blocks:
-- MPC7400 G4 MAC running Yellowdog Linux with a 2.4.18 Kernel. Thanks to Jon Harrison.
----- */
| | bleem1998 回复于:2005-04-09 15:24:07
| 好长阿
我觉得用一个select就可以解决5秒的问题
如果想直接接收到键盘字符而不用回车来确认
用一个tcsetattr也解决了
| | dzbjet 回复于:2005-04-10 16:13:06
| 你不会再信号处理函数中发送一个自定义的控制字符给getchar(),然后判断一下,如果是你发送的控制字符,就说明是超时,。。。。。。。。
| | zi_ji 回复于:2005-04-10 16:29:16
| 我觉得把signal放在alarm上面就行
| | spirn 回复于:2005-04-20 01:28:48
| 原来不行的原因是即使超时,最后还是跑回getchar里面去,所以程序无论怎么超时都会停在哪里
不过在同一个进程内部用这种方式不好。例如在getchar的内部分配了一些资源,然后由于超时强行恢复堆栈跳出来,那之前已经分配的资源就没有人释放了。所以除非你确定timeout会跳过的代码里面不会导致资源泄漏,否则就不要在同一个进程内部用这种机制
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <setjmp.h>
#define TIMEOUT 5
void sigProcess(int);
static jmp_buf env;
main(void)
{
int ret ;
printf("The program is about to get a character from the keyboard:\n");
alarm(TIMEOUT);
signal(SIGALRM,sigProcess);
if ((ret=setjmp(env))==0){
getchar();
alarm(0) ; //注意保护
printf("haha\n");
return 0 ;
}
alarm(0) ;//这是一个好习惯
printf("ret=%d\n",ret);
}
void sigProcess(int signo)
{
signal(SIGALRM,SIG_DFL);
printf("In the signal process function: TIMEOUT\n");
longjmp(env, 5);
}
| |
|