Ncurses和realtime(在C、unix中实现)

Ncurses和realtime(在C、unix中实现),c,ncurses,time.h,C,Ncurses,Time.h,我试图用C语言实现一个使用ncurses的游戏。我必须显示当前时间(时间必须每秒更新),我的while循环如下所示 while(1) { clk = time(NULL); cur_time = localtime(&clk); mvprintw(0,1,"%d %d %d",cur_time->tm_hour,cur_time->tm_min,cur_time->tm_sec); int key = getch() //othe

我试图用C语言实现一个使用ncurses的游戏。我必须显示当前时间(时间必须每秒更新),我的while循环如下所示

while(1)
{
    clk = time(NULL);
    cur_time = localtime(&clk);
    mvprintw(0,1,"%d %d %d",cur_time->tm_hour,cur_time->tm_min,cur_time->tm_sec);
    int key = getch()
    //other stuff
}

我的问题是,只有当我按下一个键时,时间才会刷新。这是一种无需按键即可刷新时间的方法吗(同时也可以实现)?

这里的解决方案是使用非阻塞IO或使用线程。但是,使用线程会给您带来一个新的问题,即在任何给定的时间只有一个线程可以使用诅咒,因此您需要使用锁或类似的锁来防止其他线程在该时间点使用诅咒。当然,一种解决方案是让一个线程负责更新屏幕内容,而其他线程只需向该线程发送消息“我想在X,Y的屏幕上显示”

这是一种非常丑陋的黑客行为,它只支持一个stdio函数:fgetc()。顺便说一句,还可以添加其他的。它通过设置计时器工作,如果在读取单个字符之前警报响起,则返回-2值(记住:-1表示EOF)

它不能与任何其他curses的wgetXXX()函数一起工作,这些函数可以直接调用fgetc()(etc)。YMMV

但是,在一般情况下,我认为您应该调查wgetch_事件()

#包括
#包括
#包括
#包括
#包括
跳下去;
int my_fgetc(文件*fp,未签名超时);
无效信号处理器(int signr);
无效信号处理器(int signr){
开关(信号器){
案例标志:
siglongjmp(_跳跃,1);
打破
违约:
打破
}
}
int my_fgetc(文件*fp,未签名超时)
{
报警(超时);
开关(sigsetjmp(_跳转,-1)){
案例0:
报警(0);
返回fgetc(fp);
案例1:
返回-2;
违约:
返回-3;
}
}
int main()
{
int rc;
信号机(信号机、信号处理机);
rc=setvbuf(标准输入,空值,_-IONBF,0);
printf(“setvbuf(_IONBF)=%d\n”,rc);
而(1){
rc=我的fgetc(标准1);
printf(“my_fgetc(NULL)=%d\n”,rc);
}
返回0;
}

您可以使用以下几个功能:

  • 诺德利
  • 超时
  • 内部节点延迟(窗口*win,布尔bf)

    将bf设置为true以使getch()非阻塞

    无效超时(整数延迟)

    延迟以毫秒为单位,因此如果将其设置为1000,则getch将在一秒钟后超时


    在这两种情况下,如果没有输入,getch将返回ERR

    问题在于stdin上的阻塞I/O。您需要一种使用非阻塞I/O的方法。(我不知道(n)curses是否实现了某种使用非阻塞I/O的方法。我想是的)函数wgetch_events()似乎满足了您的需要。(注意:我从未使用过它,我只是在ncurses.h中查找它)这是一个充满漏洞的地方。首先,你在收到一个字符后不会重置警报,因此警报可能会在处理某些东西时发出,你直接跳回my_getc,堆栈和所有东西都设置为该代码-如果你这样做,肯定会发生不好的事情。然后,在从fgetc返回和警报响起之间进行一场竞赛。当然,它可能在大部分时间都能工作,但是让它运行一段时间,运行一些字符,它肯定会掉下来。这是正确的。这只是一个演示。处理程序也应该通过sigaction()安装为无种族限制。第二个问题是curses/termio可能使用0.5秒的延迟来计时转义字符串。(区分裸ESC和实际序列的开始)。注意:我更新为仅添加报警(0);由于OP已经使用了ncurses,因此在ncurses中有很多方法可以进行键的非阻塞读取(它还有一个timeout()函数)。或者您可以在stdin上使用select()或poll(),并在超时时使用。
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <signal.h>
    #include <setjmp.h>
    
    sigjmp_buf the_jump;
    
    int my_fgetc(FILE *fp, unsigned timeout);
    void sig_handler(int signr);
    
    void sig_handler(int signr) {
            switch (signr) {
            case SIGALRM:
                  siglongjmp(the_jump,1);
                  break;
            default:
                  break;
            }
    }
    
    int my_fgetc(FILE *fp, unsigned timeout)
    {
    alarm( timeout);
    
    switch (sigsetjmp(the_jump, -1)) {
    case 0:
            alarm(0);
            return fgetc (fp);
    case 1:
            return -2;
    default:
            return -3;
            }
    }
    
    int main()
    {
    int rc;
    signal(SIGALRM, sig_handler);
    
    rc = setvbuf(stdin, NULL, _IONBF, 0);
    printf("setvbuf(_IONBF) = %d\n", rc);
    while (1) {
            rc = my_fgetc(stdin, 1);
            printf("my_fgetc(NULL) = %d\n", rc);
            }
    
    return 0;
    }