各位大佬请帮忙看看我的程序问题出在哪里? 请不吝赐教!

发表于:2007-05-26来源:作者:点击数: 标签:
我写了一个程序,希望用户从键盘输入一个字符[getchar()],如果5秒钟过去了,用户仍未输入字符,则继续执行getchar()后的代码,但我的程序却始终在等待键盘输入,如没有输入,则无法执行到后面的代码,请各位大佬看看问题出在哪里? 请不吝赐教!!! 我的程

我写了一个程序,希望用户从键盘输入一个字符[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_clearcase/" target="_blank" >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);
}

原文转自:http://www.ltesting.net

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)