2012-06-26 10 views
22

W C++ 11 funkcje czasu oczekiwania działają zgodnie z oczekiwaniami tylko wtedy, gdy używany jest stały zegar (to znaczy taki, który porusza się tylko do przodu z niezmienną szybkością). Ponieważ system_clock nie jest stabilny zegar, co oznacza, że ​​kod ten sposób mogą zachowywać się dość zaskakująco:Kiedy należy używać funkcji C++ 11 * _until timeout zamiast odpowiedniej funkcji * _for?

using namespace std::chrono; 
std::this_thread::sleep_until(system_clock::now() + seconds(10)); 

To spowoduje, że bieżący wątek spać przez 10 sekund, chyba że zegar systemowy jest regulowana w okresie uśpienia, na przykład, na czas letni. Jeśli zegar zostanie cofnięty o godzinę podczas snu, bieżący wątek będzie spał przez godzinę i 10 sekund.

Z tego, co wiem, każda funkcja limitu czasu w C++ 11 ma odpowiednią funkcję , która zajmuje czas zamiast punktu czasowego. Na przykład, powyższy kod może zostać przepisany w następujący sposób:

using namespace std::chrono; 
std::this_thread::sleep_for(seconds(10)); 

W *_for funkcje nie powinny się martwić, że się zegarów skorygowanych gdy funkcja jest wykonywany, bo po prostu powiedzieć, jak długo czekać, co nie czas powinien być, gdy skończy się czas oczekiwania.

Ten problem dotyczy więcej niż funkcji uśpienia, tak samo jest w przypadku czekania opartego na timeoutie na futures i funkcjach try_lock.

Jedyna sytuacja, w której mogę sobie wyobrazić to sensu, aby użyć funkcji *_until z niepewną zegar będzie, gdy chcesz wziąć regulacji zegara pod uwagę, na przykład, chcesz spać aż do następnej środy na 3: 30:00, nawet jeśli od czasu do czasu następuje zmiana czasu letniego lub z tego okresu. Czy istnieją inne sytuacje, w których funkcje *_until mają więcej sensu niż funkcje *_for? Jeśli nie, to czy można z całą pewnością powiedzieć, że funkcje limitu czasu w trybie *_for powinny być preferowane w stosunku do funkcji *_until?

+0

Czy to nie zależy od _stotyności _clock_? Czy 'wait_for' i' wait_until' naprawdę zamierzają działać inaczej w obsłudze "skoków zegara"? –

+0

@ K-ballo: Właśnie dlatego specjalnie wspomniałem o stabilności zegarów i ta godzina systemowa nie jest stała. Funkcje '_for' i' _until' zachowują się różnie w odniesieniu do regulacji zegara, ale to, co _intention_ jest, nie jest dla mnie jasne. – KnowItAllWannabe

+1

Ciągłość_ 'system_clock' jest w rzeczywistości zależna od implementacji. –

Odpowiedz

9

Zadzwoń pod numer xxx_until, jeśli masz termin. Typowy przypadek użycia to miejsce, w którym masz twardy limit dla sekcji kodu, która zawiera wiele czekania lub gdzie czas zużywany przez każdy krok przed oczekiwaniem jest nieprzewidywalny.

np.

void foo() { 
    std::chrono::steady_clock::time_point const timeout= 
    std::chrono::steady_clock::now()+std::chrono::milliseconds(30); 

    do_something_which_takes_some_time(); 

    if(some_future.wait_until(timeout)==std::future_status::ready) 
    do_something_with(some_future.get()); 
} 

To będzie przetwarzać tylko wartość z some_future jeśli jest ona gotowa w ciągu 30ms od początku, w tym czas potrzebny na do_something_which_takes_some_time().

Tak jak w tym przykładzie, większość przypadków użycia funkcji będzie używać stałego zegara, aby uzyskać przewidywalny czas oczekiwania.

Jedynie w tym przypadku można sobie wyobrazić, stosując XXX_until funkcji przy nieustalonych zegara (jak std::chrono::system_clock) jest, gdy czas oczekiwania jest widoczna przez użytkownika, oraz w zależności od wartości wybranych zegara. Przykładem może być budzik lub program przypominający, program do tworzenia kopii zapasowych uruchamiany "o północy" to kolejny.

4

Jednym z przypadków użycia funkcji sleep_until jest sytuacja, w której użytkownik chce spać do określonego czasu, a nie do określonego czasu.

Na przykład, jeśli masz wątek, który powinien być aktywowany tylko o 15:00 każdego dnia, musisz obliczyć czas trwania (łącznie z obsługą czasu letniego i roku przestępnego) do użycia z sleep_for, lub możesz użyć sleep_until.

+1

Budzik jest doskonałym przykładem czegoś, co powinno uwzględniać czas letni. Twoje godziny pracy są dostosowane do czasu letniego, dlatego też Twój budzik. –

2

Jeden dobry użytek dla sleep_until jest w stałych pętlach czasowych (takich jak pętle gry). Jeśli nie masz pewności, jak długo potrwa przetwarzanie cyklu, ale musi to być wartość minimalna, możesz zwiększyć punkt czasowy do spania do końca okresu cyklu. Na przykład:

// requires C++14 
#include <iostream> 
#include <thread> 
#include <chrono> 

using namespace std; 
using namespace std::chrono; 
using namespace std::literals; 

int main() 
{ 
    auto start_time = steady_clock::now(); 

    for (auto i = start_time; i <= start_time + 1s; i += 50ms) { 
    this_thread::sleep_until(i); 
    cout << "processing cycle..." << endl; 
    } 

    return 0; 
} 

ale potem już zapewne dostał śledzić lag gdy cykl trwa dłużejniż czas przyrostu.

Chodzi o to, że naiwnie sleep_for, będziesz spać swój okres cyklu plus czas potrzebny na uruchomienie kodu w pętli.

Powiązane problemy