• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Użycie Promise , Future do obliczenia iloczynu skalarnego w 10 wątkach

Object Storage Arubacloud
0 głosów
377 wizyt
pytanie zadane 18 stycznia 2020 w C i C++ przez polskiPiter Początkujący (370 p.)

Dzień dobry:

Mam takie zadanie 

"Napisz funkcję liczącą iloczyn skalarny dwóch wektorów przekazanych jako std::vector (można założyć, że wektory mają takie same rozmiary). Jako trzeci argument funkcja ma przyjmować obiekt typu std::promise, który zostanie użyty do zwrócenia wyniku.

Funkcja main powinna uruchomić 10 wątków, które policzą iloczyn skalarny powyższą funkcją, poczekać na wyniki obliczeń (używając mechanizmu future) i wypisać na ekran ich sumę."

Narazie napisałem to :

#include <iostream>
#include <thread>
#include <future>
#include <vector>


void iloczyn_skalarny(std::vector<double>a,std::vector<double>b,std::promise<double>&pro)
{
	double result=0;
	for(size_t i=0; i<a.size(); i++)
	{
		result +=a[i]*b[i];
	}
	//std::cout<<result<<std::endl;
	pro.set_value(result);
}

const int N=10;

int main()
{
	std::vector<double>a = {2,3,4};
	std::vector<double>b = {5,6,7};
	

	for(int i=0; i<N; i++)
	{
		std::promise<double>pro;
		std::future<double> fut = pro.get_future();
		std::thread t(iloczyn_skalarny,a,b,std::ref(pro));
		std::cout<<fut.get()<<std::endl;
		t.join();
	}

	return 0;
}

Czytając jak to działa to musiałbym zrobić osobny obiekt promise, obiekt future dla każdego threada aby to zadziałało. Może mi ktoś podpowiedzić jak powinniem to zrobić tak aby to było zgodne z treścią zadania oraz wytłumaczył mi jak działa ten mechanim future, promise ?

2 odpowiedzi

+1 głos
odpowiedź 19 stycznia 2020 przez j23 Mędrzec (194,920 p.)

Tak to widzę:

int main ()
{
    std::vector<double> a = { 2, 3, 4 };
    std::vector<double> b = { 5, 6, 7 };
    
    std::promise < double > pro[N];

    for (int i = 0; i < N; i++) {
        std::thread(iloczyn_skalarny, a, b, std::ref (pro[i])).detach();
    }

    for (int i = 0; i < N; i++) {
        std::cout << pro[i].get_future().get() << '\n';
    }

    return 0;   
}

 

komentarz 19 stycznia 2020 przez polskiPiter Początkujący (370 p.)
edycja 19 stycznia 2020 przez polskiPiter
@j23,

Możesz mi wytłumaczyć , dlaczego nie ma joina dla threada oraz po co ten detach() ??
1
komentarz 19 stycznia 2020 przez polskiPiter Początkujący (370 p.)

@j23,


int main ()
{
    std::vector<double> a = { 2, 3, 4 };
    std::vector<double> b = { 5, 6, 7 };
     
    std::promise < double > pro[N];
	std::vector<std::thread>t ;

    for (int i = 0; i < N; i++) {
        //std::thread(iloczyn_skalarny, a, b, std::ref (pro[i])).detach();
		t.push_back(std::thread(iloczyn_skalarny, a, b, std::ref (pro[i])));
    }
 
    for (int i = 0; i < N; i++) {
        std::cout << pro[i].get_future().get() <<": "<<i<<'\n';
		t[i].join();
	}
 
    return 0;   
}

A gdybym zrobił tak, to też byłoby poprawne ?

komentarz 19 stycznia 2020 przez j23 Mędrzec (194,920 p.)

Może i poprawne, ale nie widzę sensu czekać na zakończenie wątku (join), skoro możesz pobrać w sposób bezpieczny (get) wartość zwróconą przez ten wątek. Dlatego dałem detach, żeby odłączyć wątek od obiektu klasy std::thread.

+1 głos
odpowiedź 19 stycznia 2020 przez mokrowski Mędrzec (155,460 p.)

Ja bym to napisał tak:

#include <iostream>
#include <thread>
#include <future>
#include <vector>
#include <cstddef>

void iloczyn_skalarny(std::vector<double> a, std::vector<double> b, std::promise<double>& pro)
{
    double result = 0.0;
    std::size_t idx = a.size();
    while(idx--) {
        result += a[idx] * b[idx];
    }
    pro.set_value_at_thread_exit(result);
}

constexpr static std::size_t N = 10;

int main()
{
    std::vector<double> a = {2, 3, 4};
    std::vector<double> b = {5, 6, 7};

    std::promise<double> pro[N];

    for(auto& pr: pro) {
        std::thread(iloczyn_skalarny, a, b, std::ref(pr)).detach();
    }

    double result = 0.0;
    for(auto& pr: pro) {
        result += pr.get_future().get();
    }

    std::cout << result << '\n';
}

Obiekt std::promise, wymaga pobrania std::future aby uzyskać informację o wartości ustawianej w std::promise. Z zasady, std::promise służy do ustawiania wartości oraz ew. wyjątku ( jego set_exception(...) ). Tak wartość jak i wyjątek (będzie rzucony w momencie uzyskania wartości), można uzyskać z std::future wyprowadzonej z std::promise.

Wynik skalarnego iloczynu ustawiany być powinien na zakończeniu działania wątku ( pro.set_value_at_thread_exit(result) ) . Stąd jak już będzie ustawiony, jest pewne że wątek już nie działa. Nie jest pewne że nie działa jeśli robisz zwykłe ustawienie ( pro.set_value(result) ). Tak, to raczej zły zbieg okoliczności jeśli jeszcze działa bo przecież "ten set.. jest ostatni". Przy aplikacjach wielowątkowych, przyjmij że zły zbieg okoliczności zawsze zachodzi... to jest pewne :-/

Przy takiej obsłudze  nie ma sensu czekać na zakończenie wątku, stąd jest on odłączany ( std::thread(iloczyn_skalarny, a, b, std::ref(pr)).detach(); ). Całość aplikacji, synchronizowana jest przez pobranie wartości z std::future wyprowadzonego z std::promise.

Dodatkowo polecono Ci, aby wyświetlić sumę wyników iloczynów skalarnych. Oczywiście nie ma to większego logicznego sensu... no ale to ćwiczenie :) Dlatego sumuję w pętli w main() wszystkie std::future wyprowadzone z std::promise w tablicy.

Nie ma także sensu w każdym przypadku pracowicie iterować w zakresie [0, 10) tradycyjnym for(...). Wiadomo że elementów jest 10 bo tyle ma tablica pro[...].

komentarz 19 stycznia 2020 przez j23 Mędrzec (194,920 p.)
edycja 19 stycznia 2020 przez j23

Nie jest pewne że nie działa jeśli robisz zwykłe ustawienie

W tym przypadku (wątki detached) to IMO nie ma znaczenia.

Podobne pytania

0 głosów
1 odpowiedź 989 wizyt
pytanie zadane 30 października 2020 w C i C++ przez Incognitoo Nowicjusz (120 p.)
0 głosów
2 odpowiedzi 261 wizyt
pytanie zadane 4 października 2015 w C i C++ przez radek024 Szeryf (77,160 p.)
0 głosów
3 odpowiedzi 1,475 wizyt

92,578 zapytań

141,426 odpowiedzi

319,653 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...