Mechanizmy czasowe umożliwiają zaplanowanie, aby jądro systemu operacyjnego powiadamiało aplikację po upływie określonego czasu. Zazwyczaj będziesz ich używać, podając dwie informacje. Najpierw musisz określić, ile czasu powinien zająć minutnik przed powiadomieniem. Po drugie, musisz przygotować funkcję zwrotną, która będzie działać, gdy pojawi się to powiadomienie.

Tradycyjne podejście do timerów

Mechanizmy czasowe w systemach Linux i Unix ewoluowały, aby służyć różnym potrzebom. Różne podejścia mogą pomóc w rozwiązaniu różnych rodzajów problemów. Jednak często zobaczysz pierwszą wersję alarm() mechanizm nadal w użyciu.

Funkcja alarmu to najprostszy sposób na użycie timera; oto jego prototyp:

bez znakuintalarm(bez znakuint sekundy);

Korzystając z tej metody, możesz określić czas tylko w pełnych sekundach. Gdy czas się skończy, system operacyjny wysyła SIGALRM sygnał do aplikacji. Aby przetworzyć wygaśnięcie licznika w swojej aplikacji, powinieneś również zdefiniować funkcję zwrotną.

Oto przykład funkcji obsługi sygnału:

instagram viewer
#włączać
#włączać
#włączać
#włączać

próżniatimer_callback(int znak)
{
czas_t teraz = czas (ZERO);
drukuj("Sygnał %d złapany na %li", signum, teraz);
}

intGłówny()
{
sygnał (SIGALRM, timer_callback);
alarm(1);
spać(3);
zwrócić0;
}

Ten kod podnosi a SIGALRM sygnał po 1 druga. Jeśli chcesz zwiększyć opóźnienie timera do pięciu sekund, po prostu zadzwoń alarm (5) zamiast. Aby zatrzymać stoper, podaj wartość 0: alarm (0).

Gdy czas się skończy, używany zegar nie będzie się co jakiś czas restartował. Na przykład, jeśli chcesz opóźnić o kolejną sekundę, powinieneś zrestartować mechanizm z kolejnym wywołaniem alarm().

Pomimo łatwości użycia ta metoda ma pewne wady:

  • Tylko jeden timer na raz.
  • Brak okresowej obsługi timera.
  • Okres czasu można podać tylko w wielokrotnościach pełnych sekund.
  • Nie ma sposobu, aby dowiedzieć się, ile czasu pozostało na zegarze.

Zapisz przykładowy kod podany powyżej jako alarm.c. Kiedy kompilujesz i uruchamiasz to, program wywoła timer_callback funkcja po jednej sekundzie. Następnie będzie czekać przez pozostałe dwie sekundy z powodu spać (3) linii, a następnie zakończ.

$ gcc -o alarm alarm.c
$ czas ./alarm
Sygnał 14 złapany na 1653490465
prawdziwe 0m1.004s
użytkownik 0m0.000s
sys 0m0.003s

Powodem użycia polecenia time jest możliwość zobaczenia czasów. Ale jeśli spojrzysz na wynik, całkowity czas działania nie wynosi trzech sekund. Wynika to z SIGALRM sygnał z alarm (1) kiedy upłynie pierwsza sekunda, podczas gdy wywołanie systemowe spowodowane działaniem funkcji uśpienia (3). Gdy ten sygnał nadejdzie, przerywa wywołanie systemowe zainicjowane przez spać (3).

Korzystanie z czasomierza interwałowego

Mechanizm timera interwałowego był po raz pierwszy dostępny w wersji 4.2 BSD. To było później standaryzowane przez POSIX. Jego główne zalety w stosunku do tradycyjnego alarm() w oparciu o metodę timera to:

  • Zapewnia rozdzielczość mikrosekundową.
  • Umożliwia bardziej szczegółowe kontrolowanie pomiaru czasu w trzech różnych trybach.
  • Możliwe jest jednokrotne ustawienie i okresowe działanie.
  • Można dowiedzieć się, jak długo jest obecny w danym momencie.

Prototypy funkcji używane do operacji timera interwałowego są następujące:

#włączać

intsettimer(int który, stały struct itimerval *nowaWartość, struct itimerval *staraWartość);
intgettimer(int który, struct itimerval *wartość);

strukturaitimerval
{
strukturaczasitInterval;// następna wartość
strukturaczasitValue;// Bieżąca wartość
};

strukturaczas
{
długie tv_sec;
długie telewizja_usec;
};

Jeśli chcesz ustawić licznik interwałów, musisz użyć itimerval struktura. Będziesz musiał przekazać wartość używając tej struktury jako drugiego argumentu do Ustaw minutnik funkcjonować.

Na przykład zegar interwałowy, który będzie powiadamiał aplikację przez 1 sekundę, a następnie co 300 milisekund, można ustawić w następujący sposób:

strukturaitimervalnowyZegar;
strukturaitimervaloldTimer;

newTimer.itValue.tv_sec = 1;
newTimer.itValue.tv_usec = 0;

newTimer.itInterval.tv_sec = 0;
newTimer.itInterval.tv_usec = 300 * 1000;

settimer (ITIMER_REAL, &newTimer, &oldTimer);

Jeżeli przed ustawieniem nowych wartości jest aktywny timer interwału, jego wartości są przenoszone na adres zmiennej itimerval typ nadany trzeciemu parametrowi funkcji.

Możesz ustawić trzy różne typy timerów za pomocą mechanizmu timera interwałowego. Określ typ timera w pierwszym parametrze settimer():

Typ timera Sygnał Wyjaśnienie
ITIMER_REAL SIGALRM Niezależnie od czasu spędzonego przez aplikację, liczony na podstawie całkowitego czasu, który upłynął.
ITIMER_VIRTUAL SIGVTALRM Obliczane w czasie, gdy aplikacja działa tylko w trybie użytkownika.
ITIMER_PROF SIGPROF Obliczany na podstawie sumy czasu spędzonego przez aplikację w trybie użytkownika i systemu.

Z tej tabeli widać, że ITIMER_REAL wpisz wysyła a SIGALRM sygnał, tak jak alarm() funkcjonować.

Korzystanie z licznika interwałów i alarm() w tej samej aplikacji będzie mylące. Chociaż możesz ponownie sprawdzić pozostały czas za pomocą gettimer(), nie ma sensu używać ich jednocześnie.

Oto przykład definiowania funkcji obsługi sygnału za pomocą nagłówek debugowania:

#włączać
#włączać
#włączać
#włączać
#włączać
#włączać
#włączać
#włączać „./debug.h”

próżniatimer_callback(int znak)
{
strukturaczasTeraz;
gettimeofday(&teraz, ZERO);
drukuj("Sygnał %d złapany na %li.%03lja ", signum, teraz.tv_sec, teraz.tv_usec / 1000);
}

intGłówny()
{
bez znakuint pozostały = 3;

strukturaitimervalnowy_timer;
strukturaitimervalold_timer;

new_timer.it_value.tv_sec = 1;
new_timer.it_value.tv_usec = 0;
new_timer.it_interval.tv_sec = 0;
new_timer.it_interval.tv_usec = 300 * 1000;

settimer (ITIMER_REAL, &nowy_timer, &stary_timer);
sygnał (SIGALRM, timer_callback);

podczas gdy (sen (pozostały) != 0)
{
jeśli (errno == EINTR)
debugf("sen przerwany przez sygnał");
w przeciwnym razie
errorf("błąd snu %s", strerror (errno));
}

zwrócić0;
}

Powyższy kod wykorzystuje spać() funkcja czekać przez trzy sekundy. W tym czasie zegar interwałowy działa najpierw przez jedną sekundę, a następnie z interwałem 300 milisekund.

Dla lepszego zrozumienia zapisz i skompiluj przykładowy kod z nazwą przedział.c:

$ gcc -o interwał interwał.c
$ czas ./interwał
Sygnał 14 złapany 1653493614.325
debug: sen przerwany przez sygnał (główny interwał.c: 36)
Sygnał 14 złapany 1653493614.625
debug: sen przerwany przez sygnał (główny interwał.c: 36)
Sygnał 14 złapany 1653493614.925
debug: sen przerwany przez sygnał (główny interwał.c: 36)
Sygnał 14 złapany 1653493615.225
debug: sen przerwany przez sygnał (główny interwał.c: 36)
Sygnał 14 złapany na 1653493615.525
...

Jak widać z danych wyjściowych po uruchomieniu timera, wywołuje on funkcję zwrotną co 300 milisekund.

Jednak po odczekaniu trochę dłużej zauważysz, że aplikacja się nie kończy. Kontynuuje uruchamianie funkcji zwrotnej co 300 milisekund. Jeśli zwiększysz wartość interwału w milisekundach, zobaczysz, że aplikacja kończy działanie. Wynika to z obszaru użytkowania spać() funkcjonować.

Znaczenie korzystania z timerów w systemie Linux

Szczególnie w przypadku aplikacji czasu rzeczywistego ogromne znaczenie ma mechanizm timera. Jest to również rozwiązanie służące do optymalizacji wydajności. Możesz nawet użyć go do pomiaru czasu pracy lub opóźnień w swojej aplikacji. Ważne jest, aby używać mechanizmów czasowych do śledzenia czasu, który upłynął i zdarzeń zmiany czasu.

Jak kompilować i instalować oprogramowanie ze źródła w systemie Linux?

Czytaj dalej

DzielićĆwierkaćDzielićE-mail

Powiązane tematy

  • Programowanie
  • Programowanie
  • Wskazówki dotyczące Linuksa

O autorze

Fatih Küçükkarakurt (10 opublikowanych artykułów)

Inżynier i programista, pasjonat matematyki i technologii. Zawsze lubił komputery, matematykę i fizykę. Opracował projekty silników gier, a także uczenie maszynowe, sztuczne sieci neuronowe i biblioteki algebry liniowej. Ponadto kontynuuje prace nad uczeniem maszynowym i macierzami liniowymi.

Więcej od Fatiha Küçükkarakurt

Zapisz się do naszego newslettera

Dołącz do naszego newslettera, aby otrzymywać porady techniczne, recenzje, bezpłatne e-booki i ekskluzywne oferty!

Kliknij tutaj, aby zasubskrybować