Reputation:
I'm currently programming Tetris in C++. Right now I am at the stage where I have finished writing the program but I still need to fix a few bugs and optimize performance.
That being said, one of the flaws in my program is that it can only handle one key-press per second. I need it to handle at least three. You can see the flaw demonstrated by this code:
//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;
}
As you can see, the program operates by setting up a one second interval timer and timeval. Because both timers use ints to determine how much time has passed, they cannot be more precise than one second. How can I modify my program to be more precise?
My thought was to copy the value of tv1
to a third value if a key was pressed and then wait for input again but for whatever value time that tv1
was. For example if I press a key when there is only half a second left, the value 0.5
would be taken from tv1
and copied to another variable. Then the program would only wait for half a second for input, instead of the full second. This didn't work, however, because tv1
only ever equals 1
or 0
.
Upvotes: 3
Views: 173
Reputation: 5416
Try to use struct timeval
and gettimeofday()
in sys/time.h
. You can achieve microseconds resolution.
Manpage: http://linux.die.net/man/3/gettimeofday
Further info: http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
EDIT:
In Linux (not portable to MinGW under Windows) you could also use poll()
(see here), which lets you wait for milliseconds. That would be more efficient because poll
suspends the thread execution until time is out.
//Timer function.
void *Timer(void*) {
poll(0, 0, 100); //Suspend thread for 100 ms.
pthread_exit(NULL);
}
The poll
function is declared in poll.h
Upvotes: 5
Reputation: 28872
The problem here is that pthread_join
suspends the main thread until the timer thread completes. You will therefore miss any user input that comes during or after the join. Since you are already using select
, you might as well make use of the timeout built into the select
statement. If you keep a watch of time elapsed, you can achieve the same effect without the timer thread.
Upvotes: 0