Wpis z mikrobloga

Język C++11 i mam taki problem projektowy:

Na pewne zadanie obliczeniowe przewidziane jest X czasu. Jeżeli się uda je rozwiązać to w porządku, a jeżeli nie to trudno - grunt, żeby nie przekroczyć czasu. Chciałbym rozwiązać wiele takich zadań, każde w osobnym wątku. Mam już coś takiego:

list threads;
for (problem : problems) {
____threads.push_back(solve(problem));
}
for (thread : threads) {
____thread.join();
}
I to ścierwo działa, bardzo ładnie działa, ale oczywiście skończy jak skończy i zwraca wszystkie rozwiązania (są one wkładane do kontenera - monitora). Wie ktoś jak inteligentnie zmodyfikować to rozwiązanie tak, żeby przestrzegało ograniczeń czasowych? Podejrzewam, że jest to dość typowy przypadek dlatego nie chce wymyślać koła na nowo.

EDIT: Czas rozwiązania problemu bardzo się różni dla poszczególnych przypadków dlatego zawsze mam pewność, że przy racjonalnym czasie część zdąży się rozwiązać, a część nie.

#programowanie #cpp #cpp11
  • 11
@losiul: Problemem jest funkcja solve(), która może wykonywać się zbyt długo. Jestem w stanie sprawdzić czy czas został przekroczony bezpośrednio przed nią i po niej, ale to mnie nie ustawia. Miałem nadzieję na kontrolę czasu w innym wątku (głównym) i uśmiercenie tych, które jeszcze pracują kiedy czas się skończy. :<

ach, nie uzywaj list, to jest praktycznie bez sensu w 99% wypadkow ; )


To jak inaczej?
@Onoki: nie wiem czy istnieje jakis cross-platformowy sposob na przerwanie dzialajacego watku, bez modyfikacji funkcji ktora odpalasz.

Co do listy, vector jest szybszy prawie w kazdym wypadku, zeby go zbudowac zrob tak:

vector threads;

for(problem : problems)

threads.emplace_back(thread([&](){solve(problem);}));
Co do listy, vector jest szybszy prawie w kazdym wypadku


@losiul: To ciekawe. Byłem przekonany, że lista jest zbudowana tak, że każdy poprzednik zawiera wskaźnik na następnik (i być może odwrotnie), a elementy mogą sobie być rozrzucone po pamięci. Wektor natomiast musi być przebudowany (skopiowany w inne miejsce) po każdej zmianie rozmiaru i dlatego jest wolnym kontenerem.

Czym się różni emplaceback() od pushback()?

Jakbyś miał jakieś profesjonalne porównanie wydajności
@Onoki: tez tak kiedys myslalem, ale chodzi o to ze vector miesci sie w cache, a to znacznie przyspiesza operacje. Poszperaj, w sieci jest sporo porownan ; ).

std::thread jest niekopiowalny, dlatego musisz uzyc r-value reference, ktora obsluguje emplace_back. W C++11 pojawilo sie move semantics, poczytaj jesli nie slyszales o tym.
Czym się różni emplaceback() od pushback()?


@Onoki:

push_back
bierze universal reference na typ, jaki podales w wektorze, co w praktyce zazwyczaj oznacza, ze najpierw musisz wywolac konstruktor obiektu, potem zrobic na nim

move
albo kopie, zeby dopiero go dodac do vectora. Natomiast

emplace_back
przekazuje od razu podane argumenty bezposrednio do konstruktora (perfect forwarding), ktory dzieki temu wywoluje sie tylko raz. Np. jak masz

std::vector>
, to robisz

emplace_back(4.3f, 2)
i sie
@Onoki najlepiej będzie jak zaimplementujesz jakąś wymianę komunikatów między wątkami i zabijesz je w inteligentny sposób wysyłając rozkaz "quit", inaczej będziesz miał wycieki pamięci i zasobów - w najlepszym wypadku (wyobraź sobie, ƶe zabijasz wątek w momencie gdy trzyma on mutexa do jakiegoś globalnego zasobu).