nanosleep(2)

NAZWA
nanosleep - usypia z wysoką rozdzielczością

BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)

SKŁADNIA
#include <time.h>

int nanosleep(const struct timespec *duration,
              struct timespec *_Nullable rem);

    Wymagane ustawienia makr biblioteki glibc (patrz feature_test_macros(7)):

nanosleep():
    _POSIX_C_SOURCE >= 199309L

OPIS
nanosleep() zawiesza wykonywanie wywołującego wątku, dopóki nie upłynie co najmniej czas podany w *duration albo dopóki nie zostanie dostarczony sygnał, który wyzwoli przywołanie procedury obsługi w wątku wywołującym lub który zakończy proces.

Jeśli wywołanie zostanie przerwane przez procedurę obsługi sygnału, nanosleep zwróci -1, ustawi errno na wartość EINTR i zapisze pozostały czas do do struktury wskazywanej przez rem, o ile rem nie było równe NULL. Wartość *rem można wykorzystać do ponownego wywołania nanosleep() i dokończenia zadanej pauzy (jednak zob. UWAGI).

Do podawania interwałów czasowych z dokładnością nanosekundową, używana jest struktura timespec(3).

Wartość pola nanosekund musi być w zakresie [0, 999999999].

W porównaniu ze sleep(3) i usleep(3), nanosleep ma następujące zalety: oferuje wyższą rozdzielczość do określania czasu pauzy; POSIX.1 wyraźnie określa, że nie wpływają na nie sygnały; pozwala na łatwiejszą kontynuację uśpienia po przerwaniu przez procedurę obsługi sygnału.

WARTOŚĆ ZWRACANA
Po udanym spauzowaniu na żądany czas, nanosleep() zwróci 0. Jeśli wywołanie przerwano przez procedurę obsługi sygnału lub wystąpi błąd, zwróci -1 i ustawi errno wskazując błąd.

BŁĘDY

EFAULT
    Problem z kopiowaniem informacji z przestrzeni użytkownika.

EINTR
    Pauza została przerwana sygnałem, dostarczonym wątkowi (zob. signal(7)). Pozostały czas uśpienia został zapisany do *rem, więc wątek może łatwo wywołać ponownie nanosleep() i dokończyć pauzę.

EINVAL
    Wartość z pola tv_nsec nie była w zakresie [0, 999999999] lub tv_sec było ujemne.

WERSJE
POSIX.1 określa, że nanosleep() powinno odmierzać czas zegarem CLOCK_REALTIME (czasu rzeczywistego). Linux dokonuje tego jednak za pomocą zegara CLOCK_MONOTONIC (czasu monotonicznego). Prawdopodobnie nie ma to znaczenia, gdyż norma POSIX.1 wobec clock_settime(2) podaje, że skoki czasu w CLOCK_REALTIME nie powinny wpływać na nanosleep():

    Ustawienie wartości zegara CLOCK_REALTIME za pomocą clock_settime(2) nie powinno mieć wpływu na wątki, które są zablokowane w oczekiwaniu na usługę czasu względnego, opartą na tym zegarze, w tym funkcję nanosleep(); ... Te usługi czasu powinny zatem wygasać, gdy upłynie żądany okres, niezależnie od nowej lub starej wartości zegara.

STANDARDY
POSIX.1-2008.

HISTORIA
POSIX.1-2001.

Aby wspierać aplikacje wymagające znacznie bardziej dokładnych pauz (np. aby sterować sprzętem o krytycznych zależnościach czasowych), nanosleep() radziło sobie z pauzami do 2 milisekund w ten sposób, że oczekiwało z zajętością, z mikrosekundową precyzją, gdy było wywoływane przez wątek, działający według polityki czasu rzeczywistego, takiej jak SCHED_FIFO czy SCHED_RR. To specjalnie rozszerzenie zostało usunięte w Linuksie 2.5.39, dlatego nie jest już dostępne od jądra Linux 2.6.0.

UWAGI
Jeśli duration nie jest dokładnie wielokrotnością rozdzielczości przedmiotowego zegara (zob. time(7), to interwał ten zostanie zaokrąglony w górę, do następnej wielokrotności. Co więcej, po zakończenia pauzy, wciąż może wystąpić zwłoka przez ponownym zwolnieniem procesora w celu ponownego wykonania wątku wywołującego.

Fakt, że nanosleep() pauzuje na interwał względny może być problematyczny, jeśli wywołanie jest ponownie restartowane po otrzymaniu sygnałów przerwania, ponieważ czas pomiędzy każdym restartem i przerwaniem wywołania, spowoduje przesunięcie czasu, w jakim pauza się ostatecznie zakończy. Problemu tego można uniknąć, używając clock_nanosleep(2) z bezwzględną wartością czasu.

USTERKI
Jeśli program przechwytujący sygnały i używający nanosleep() będzie otrzymywał sygnały z dużą częstością, to przydzielanie zasobów powoduje opóźnienia i błędy zaokrąglenia w obliczeniach, dotyczących interwału pauzy oraz zwracanej wartości remain, które dokonuje jądro, co oznacza, że wartość remain może systematycznie rosnąć po kolejnych restartach wywołania nanosleep(). Aby uniknąć tego typu problemów, należy korzystać z clock_nanosleep(2) ze znacznikiem TIMER_ABSTIME, aby pauzować do terminu określonego bezwzględnie.

W Linuksie 2.4, jeśli nanosleep() zostanie zatrzymane sygnałem (np. SIGTSTP), to wywołanie zawodzi z błędem EINTR po tym, jak wątek zostanie wznowiony sygnałem SIGCONT. Jeśli wywołanie systemowe zostanie później zrestartowane, to czas jaki wątek spędził w stanie zatrzymanym nie jest liczony do czasu pauzy. Problem naprawiono w Linuksie 2.6.0 i kolejnych jądrach.

ZOBACZ TAKŻE
clock_nanosleep(2), restart_syscall(2), sched_setscheduler(2), timer_create(2), sleep(3), timespec(3), usleep(3), time(7)

TŁUMACZENIE
Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Przemek Borys <pborys@dione.ids.pl>, Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl> i Michał Kułach <michal.kulach@gmail.com>

Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 (https://www.gnu.org/licenses/gpl-3.0.html) lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.