Czy program, który nigdy nie kończy prawidłowego programu C ++?

15

Czy do zakończenia programu wymagany jest program? Innymi słowy, czy program, który działa wiecznie, jest technicznie niezdefiniowanym zachowaniem? Uwaga: nie chodzi o puste pętle. Mówiąc o programach, które na zawsze wykonują „rzeczy” (tj. Obserwowalne zachowania).

Np. Coś takiego:

int main()
{
    while (true)
    {
        try
        {
            get_input(); // calls IO
            process();
            put_output(); // calls IO, has observable behavior

            // never break, exit, terminate, etc
        } catch(...)
        {
            // ignore all exceptions
            // don't (re)throw
            // never go out of loop
        }
    }
}

Jest to raczej pytanie akademickie, ponieważ empirycznie wszystkie rozsądne kompilatory wygenerują oczekiwany kod dla powyższego rodzaju programu (zakładając oczywiście, że nie ma innego źródła UB). I tak, oczywiście, istnieje wiele programów, które nigdy się nie kończą (OS, osadzone, serwery). Jednak czasami standard jest dziwaczny, stąd pytanie.


Styczne: wiele (niektórych?) Definicji „algorytmu” wymaga, aby algorytm się zakończył , tzn. Szereg operacji, które nigdy się nie kończą, nie jest uważany za algorytm.


Styczny. Problem zatrzymania mówi, że nie może istnieć algorytm określający, czy dowolny program zakończy działanie dla danych wejściowych. Jednak w przypadku tego konkretnego programu, ponieważ nie ma gałęzi, która prowadzi do wyjścia z głównego, kompilator może łatwo stwierdzić, że program nigdy się nie skończy. Jest to jednak nieistotne, ponieważ pytanie dotyczy prawnika ds. Języka.

bolov
źródło
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Samuel Liew

Odpowiedzi:

15

W standardzie C ++ nie ma nic, co wymagałoby zakończenia programu lub dowolnego wątku. Najbliżej tego jest [intro.progress] p1 , co mówi

Implementacja może zakładać, że dowolny wątek ostatecznie wykona jedną z następujących czynności:

  • zakończyć,
  • wywołać funkcję biblioteki I / O,
  • wykonać dostęp poprzez lotną glvalue, lub
  • wykonać operację synchronizacji lub operację atomową.

[  Uwaga: Ma to na celu umożliwienie transformacji kompilatora, takich jak usuwanie pustych pętli, nawet jeśli nie można udowodnić zakończenia. -  uwaga końcowa  ]

Dopóki istnieje pewne obserwowalne zachowanie, w końcu lub tak długo, jak spędza cały czas zablokowany na operacji we / wy lub innym blokującym wywołaniu biblioteki, nie ma to zastosowania, a program jest poprawny (zakładając, że spełnia wszystkie inne kryteria ważności).

Daniel H.
źródło
„operacja We / Wy lub inne blokujące wywołanie biblioteki” - Standard jest dość przejrzysty i zawiera tylko operacje We / Wy. Dlaczego dodajesz „lub inne blokujące wywołanie biblioteki”? Ponadto operacja we / wy jest już uwzględniona we wcześniejszym „ pewnym możliwym do zaobserwowania zachowaniu”.
MSalters
1
@MSalters std::mutex::lock()to wywołanie biblioteki, które jest operacją synchronizacji, objętą czwartym punktem. Nie jest więc prawdą, że wymienione są tylko połączenia We / Wy.
Igor Tandetnik
Jeśli utknie na wejściu , ale nigdy go nie otrzyma, można dyskutować, czy liczy się to jako obserwowalne.
Daniel H
4

Tak. Od[intro.progress]

Implementacja może zakładać, że dowolny wątek ostatecznie wykona jedną z następujących czynności:

  • zakończyć,
  • wywołać funkcję biblioteki I / O,
  • wykonać dostęp poprzez lotną glvalue, lub
  • wykonać operację synchronizacji lub operację atomową.

[ Uwaga: Ma to na celu umożliwienie transformacji kompilatora, takich jak usuwanie pustych pętli, nawet jeśli nie można udowodnić zakończenia. - uwaga końcowa ]

Caleth
źródło
Uważam, że wskazany byłby krótki opis stwierdzający, że program wykonuje operacje we / wy.
KamilCuk
Tak długo, jak funkcje get_inputi put_outputw przykładzie PO „wykonują wywołanie funkcji bibliotecznej we / wy”, program powinien być poprawny, nawet jeśli się nie zakończy?
Jakiś programista koleś
@Someprogrammerdude lub uzyskaj dostęp do wartości lotnej lub atomowej, Tak
Caleth
ciekawy standardu wcześniejszego niż c ++ 11, kiedy nie było obecnego modelu pamięci.
bolov
1
compiler does not know- To nie ma znaczenia. Kompilator może wiedzieć i nie wiedzieć z punktu widzenia warstwy językowej - pytanie brzmi, czy w każdym razie jest poprawne.
KamilCuk