user1116768
user1116768

Reputation:

Hi-res Program Time

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

Answers (2)

Claudi
Claudi

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 pollfunction is declared in poll.h

Upvotes: 5

doron
doron

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

Related Questions