Jak zatrzymać zadanie (thread) w C++.

0

Jak zatrzymać zadanie z klasy thread kiedy uruchomiłem je funkcją detach(); .
Próbowałem stworzyć wskaźnik (thread*) za alokować go, wywołać funkcję thread->detach(); i potem zwolnić pamięć. Jednak to nie działa.
Ma ktoś jakiś pomysł?
Pozdrawiam, i z góry dziękuję za odpowiedź ;).

4

Zdaje się, że takie zwolnienie pamięci nic Ci nie da. To nawet UB nie jest. Natomiast rzecz jest nieco problematyczna. Tutaj podobny, mój problem:
http://4programmers.net/Forum/C_i_C++/264193-uruchamianie_funkcji_z_kontrola_czasu

tldr: Masz przekichane. Jedynym słusznym rozwiązaniem jest stworzenie std::atomic<bool> should_i_stop i sprawdzanie tego co jakiś czas w wątku.
if (should_i_stop) return ...;

Biblioteka std::thread jako tako nie ma mechanizmu przerwania pracy wątku. Możesz zrobić to natywnie. Dla przykładu (unix):
http://man7.org/linux/man-pages/man3/pthread_exit.3.html
jednak to spowoduje wycieki pamięci. Wątek zostanie "brutalnie" przerwany bez wywołania destruktorów obiektów zaalokowanych w wątku. Tj żadne mutexy nie zostaną zdjęte, żaden plik nie zostanie zamknięty a żadna zaalokowana pamięć nie zostanie zwolniona.

Właściwie każda próba przerwania wątku z zewnątrz to UB. Zatem - jak już powiedziałem - zastanów się nad jakiegoś typu komunikacją z wątkiem, która pozwala go przerwać.

0

Wywołanie std::terminate() z jakiegokolwiek wątku zakończy go "siłą" lub wyjście z funkcji, którą wywołałeś tworząc wątek.

Generalnie wykorzystując STL raczej się nie da tego inaczej zrobić, podobno boost oferuje taką funkcjonalność.

1
pingwindyktator napisał(a):

Dla przykładu (unix):
http://man7.org/linux/man-pages/man3/pthread_exit.3.html
jednak to spowoduje wycieki pamięci. Wątek zostanie "brutalnie" przerwany bez wywołania destruktorów obiektów zaalokowanych w wątku. Tj żadne mutexy nie zostaną zdjęte, żaden plik nie zostanie zamknięty a żadna zaalokowana pamięć nie zostanie zwolniona.

Akurat w pthread_exit możemy coś poradzić bo

Any clean-up handlers established by pthread_cleanup_push(3) that
have not yet been popped, are popped (in the reverse of the order in
which they were pushed) and executed. If the thread has any thread-
specific data, then, after the clean-up handlers have been executed,
the corresponding destructor functions are called, in an unspecified
order.

Czyli jeżeli dobrze rozumiem to można podać sprzątające handlery, które ogarnął co trzeba. Dodatkowo można podać też handlery do atexit(). Z windowsem jest chyba trochę gorzej bo na MSDN o TerminateThread nic o handlerach nie piszą, chociaż pewnie jest jakiś sposób, żeby to ogarnąć.

0

@stryku masz absolutną rację, natomiast to wymaga grzebania w kodzie funkcji. A jeśli już zgadzamy się na grzebanie, to dużo lepszym pomysłem jest flaga std::atomic<bool>

0
Ceki napisał(a):

Jak zatrzymać zadanie z klasy thread kiedy uruchomiłem je funkcją detach(); .
Próbowałem stworzyć wskaźnik (thread*) za alokować go, wywołać funkcję thread->detach(); i potem zwolnić pamięć. Jednak to nie działa.
Ma ktoś jakiś pomysł?
Pozdrawiam, i z góry dziękuję za odpowiedź ;).

Ja przerywam takie thready za pomocą eventów.

Znaczy tworzysz sobie globalny event np. evfinish17,
a potem sprawdzasz go po prostu, systematycznie... w tej głównej funkcji samego zainteresowanego threada.

Gdy jest on ustawiony, wtedy robisz zwyczajny return (z tej funkcji), co kończy dany thread definitywnie.

Sam event ustawiasz w innym wątku, oczywiście.. zwykle w tym głównym, na którym aplikacja jedzie...

2

To jest problem w każdym języku.
Wszelkie próby siłowego zakończania wątku kończą się poważnymi problemami, nawet jeśli język posiada garbage collector.
Jedynym rozsądnym rozwiązaniem jest dostosowanie swojego kodu by zakańczał się w kontrolowany sposób na żądanie.

Przykładowo.

class PrintHelloUntil {
    atomic_flag continueCondition;

public:
    PrintHelloUntil() {
         continueCondition.test_and_set();
    }
    
    PrintHelloUntil(const PrintHelloUntil&) : PrintHelloUntil() {}

    void operator()(int x) {
         while(continueCondition.test_and_set()) {
               cout << "Hello threads! " << x << endl;
               std::this_thread::sleep_for (std::chrono::seconds(1));
         }
    }

    void Stop() {
         continueCondition.clear();
    }
};

PrintHelloUntil worker;
auto thread1 = std::thread(std::ref(worker), 3);
std::this_thread::sleep_for(std::chrono::seconds(10));
worker.Stop();
thread1.join();

http://melpon.org/wandbox/permlink/sLQ8Vf0W3y52ILd3

0

Dziękuję wszystkim za odpowiedzi.

Problem wziął się z tego że chciałbym zrobić funkcję która łaczy się z bazą danych, i czeka na "odpowiedź" od bazy w kontekście połączenia się z nią. Gdy np. Internet jest wyłączony, tą wspomnianą odpowiedź otrzymuję po połowie minuty...podczas, gdy jeśli nie ma żadnych bodźców które mogą negatywnie wpłynąć na połączenie się z bazą, odpowiedź otrzymuję wciągu ok. 0.3 s. Ma ktoś pomysł na to aby zrobić taką funkcje która zwraca odpowiedź po 0.4s nie zważając na działającą jeszcze próbę łaczenia?

Pozdrawiam i życzę miłego dnia ;)

0

Jakiej używasz biblioteki i bazy? Nie ma tam możliwości podania timeouta?

0

Po pierwsze zgadzam się ze stryku, na pewno możesz zmienić wartość timeout (ale proponowana przez ciebie wartość 0.4 to samobójstwo dla funkcjonalności kodu).
Inne rozwiązanie to użycie asynchronicznego API (nieblokującego). Dostajesz wtedy coś co identyfikuje zadanie co pozwala ci: na żądanie anulować zadanie, dostać notyfikację o wykonaniu lub potencjalnym błędzie.

0

QSql, korzystam z wtyczki Qt add-in do visual studio ;)

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