Wątek zablokowany 2018-10-27 20:27 przez furious programming.

Co zrobić, żeby "świat" nie "przyspieszał" kiedy użytkownik np. przytrzyma Enter?

0

Witam. Szybko i zwięźle, oto kod:

#include <iostream>
#include <string>
#include <sstream>

#include <sys/types.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

using namespace std;

#define WHITESPACE " \t\n\r"

template<typename type>
inline string ToString (type p_thing)
{
    stringstream result;
    result << p_thing;
    return result.str();
}

void TrimWhitespace (string& p_string)
{
    int wsf;
    int wsb;

    wsf = p_string.find_first_not_of(WHITESPACE);
    wsb = p_string.find_last_not_of(WHITESPACE);

    if (wsf == (signed int)string::npos)
    {
        wsf = 0;
        wsb = -1;
    }

    p_string = p_string.substr(wsf, wsb - wsf + 1);
}

int main (int argc, char **argv)
{
    char buffer[2048];

    string in_buffer;
    string out_buffer;

    int pulse = 1;

    int select_result;
    int read_result;

    fd_set inputs;
    fd_set testfds;

    struct timeval timeout;
    struct timeval last_sleep;

    struct timeval sleep_time;
    struct timeval now_time;

    int secs;
    int usecs;

    const int pps = 5;

    FD_ZERO(&inputs);

    FD_SET(0,&inputs);

    gettimeofday(&last_sleep, NULL);

    while (true)
    {
        testfds = inputs;

        // 1 sec = 1 000 000 usec
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        select_result = select(FD_SETSIZE, &testfds, (fd_set*)0, (fd_set*)0, &timeout);

        // Jeżeli nic nie dostaliśmy...
        if (select_result == 0)
        {
        }
        // Jeżeli stracono połączenie...
        else if (select_result == -1)
        {
            // select error
            return 1;
        }
        // Jeżeli coś dostaliśmy...
        else if (FD_ISSET(0,&testfds))
        {
            ioctl(0, FIONREAD, &read_result);

            // Jeżeli... CO?
            if (read_result == 0)
            {
                // keyboard done
                return 0;
            }

            read_result = read(0, buffer, read_result);

            buffer[read_result] = 0;

            in_buffer = buffer;

            TrimWhitespace(in_buffer);

            pulse++;
        }

        // Jeżeli niczego nie dostaliśmy...
        if (in_buffer.empty())
        {
            out_buffer += "\nŚwiat się kręci... To już ";
            out_buffer += ToString(pulse);
            out_buffer += ". sekunda!";
            out_buffer += "\n\n<prompt> ";
            pulse++;
        }
        // ...w przeciwnym wypadku...
        else
        {
            out_buffer += "Dostałem " + in_buffer + "!";
            out_buffer += "\n\n<prompt> ";
            in_buffer.erase();
        }

        // Jeżeli jest coś do wysłania...
        if (!out_buffer.empty())
        {
            write(0, out_buffer.c_str(), out_buffer.size());
            out_buffer.erase();
        }

        // Obsługa drzemania
        if (pps > 0)
        {
            gettimeofday(&now_time, NULL);

            // Policz ile czasu trzeba się zdrzemnąć
            usecs = (int) (last_sleep.tv_usec -  now_time.tv_usec) + 1000000 / pps;
            secs  = (int) (last_sleep.tv_sec  -  now_time.tv_sec);

            while (usecs < 0)
            {
                usecs += 1000000;
                secs  -= 1;
            }

            while (usecs >= 1000000)
            {
                usecs -= 1000000;
                secs  += 1;
            }

            // Zdrzemnij się, jeśli to konieczne
            if (secs > 0 || (secs == 0 && usecs > 0))
            {
                sleep_time.tv_usec = usecs;
                sleep_time.tv_sec  = secs;

                select(0, NULL, NULL, NULL, &sleep_time);
            }

            // Zapamiętaj czas ostatniej drzemki
            gettimeofday(&last_sleep, NULL);
        }
    }

    return 0;
}

Co zrobić, żeby "świat" nie "przyspieszał" kiedy użytkownik np. przytrzyma Enter? Prosiłbym o konkretne rozwiązania, zamiast lakonicznych "man select"... ;-) Z góry dzięki,

0

IMVHO pętla powinna wyglądać tak:

  1. Oblicz czas od ostatniego „kręcenia się” (ew. od początku pracy programu, jeśli żadnego kręcenia jeszcze nie było) i odejmij go od odstępu pomiedzy kręceniami.
  2. Jesli wyjdzie wynik niedodatni, wykonaj „kręcenie”, w przeciwnym wypadku wykonaj
    2.1) select z timeoutem takim, jak obliczona róznica
    2.2) jesli select pokazał coś na wejściu, obsłuż to co na wejści, w przeciwnym wypadku jesli select zwrócił timeout, wykonaj kręcenie, jezęli żadne z tych (czyli błąd) obsłuż błąd.

1 użytkowników online, w tym zalogowanych: 0, gości: 1