我目前正在用C ++编写俄罗斯方块。现在我正处于编写程序的阶段,但我仍然需要修复一些错误并优化性能。
话虽这么说,我的程序中的一个缺点就是它每秒只能处理一次按键操作。我需要它至少处理三个。你可以看到这段代码所展示的缺陷:
//Most headers only pertain to my main program.
#include <iostream>
#include <termios.h>
#include <pthread.h>
#include <time.h>
#include <cstring>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
//Timer function.
void *Timer(void*) {
time_t time1, time2;
time1 = time(NULL);
while (time2 - time1 < 1) {
time2 = time(NULL);
}
pthread_exit(NULL);
}
int main() {
//Remove canonical buffering.
struct termios t_old, t_new;
tcgetattr(STDIN_FILENO, &t_old);
t_new = t_old;
t_new.c_lflag &= (~ICANON & ~ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &t_new);
const int STDIN = 0;
struct timeval tv, tv1;
fd_set readfds, readfds2, master;
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&readfds);
FD_ZERO(&master);
FD_SET(STDIN, &readfds);
FD_SET(STDIN, &master);
char buffer[1];
while(buffer[0] != 'q') {
pthread_t inputTimer;
pthread_create(&inputTimer, NULL, Timer, NULL);
readfds = master;
memcpy(&tv1, &tv, sizeof(tv));
if (select(STDIN+1, &readfds, NULL, NULL, &tv1) == -1) {
perror("select");
}
if (FD_ISSET(STDIN, &readfds)) {
buffer[0] = cin.get();
cout << "You entered: " << buffer << endl;
}
pthread_join(inputTimer, NULL);
cout << "Timed out.\n" << endl;
}
cout << "Game Over." << endl;
return 0;
}
如您所见,程序通过设置一秒间隔计时器和timeval来运行。因为两个计时器都使用整数来确定已经过了多少时间,所以它们不能比一秒更精确。如何更精确地修改程序?
我的想法是,如果按下某个键,则将tv1
的值复制到第三个值,然后再次等待输入,但是对于tv1
的任何值时间。例如,如果我只剩下半秒钟时按一个键,则值0.5
将从tv1
获取并复制到另一个变量。然后程序只等待半秒钟输入,而不是整秒。但是,这不起作用,因为tv1
只等于1
或0
。
答案 0 :(得分:5)
尝试使用struct timeval
和gettimeofday()
in sys/time.h
。你可以达到微秒的分辨率。
手册页:http://linux.die.net/man/3/gettimeofday
更多信息:http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
修改强>:
在Linux中(不能在Windows下移植到MinGW),你也可以使用poll()
(参见here),这可以让你等待毫秒。这会更有效,因为poll
会暂停线程执行,直到时间结束。
//Timer function.
void *Timer(void*) {
poll(0, 0, 100); //Suspend thread for 100 ms.
pthread_exit(NULL);
}
poll
函数在poll.h
答案 1 :(得分:0)
这里的问题是pthread_join
挂起主线程直到定时器线程完成。因此,您将错过在加入期间或之后出现的任何用户输入。由于您已经在使用select
,因此您也可以使用select
语句中内置的超时。如果你经常观察时间,你可以在没有计时器线程的情况下达到同样的效果。