Wielowątkowość - thread c++

Wielowątkowość - thread c++
0

Witam serdecznie. Dostałem takie zadanie aby napisać program który wyszuka minimum w tablicy (wielowątkowo - liczba wątków ustalana na etapie kompilacji). Wykorzystałem tutaj tablice wątków, alokowaną dynamicznie. Tworze nowe wątki poprzez new aczkolwiek nie mam pojęcia jak zrobić żeby program czekał aż wszystkie te wątki sie skończą i dopiero wtedy przeszukał tablice pomocniczą w której znajdują się min znalezione przez każdy wątek. Zamieszczam kod za wszelkie rady będę bardzo wdzięczny :) Czytałem troche o join ale nie mam pojęcia jak tutaj z tego skorzystać. Przy normalnym tworzeniu wątków np: thread t1(xx) thread t2(xxx) nie ma problemu bo wystarczy zrobić t1.join() t2.join().

Kopiuj
#include <iostream>
#include <thread>
#include <ctime>
using namespace std;
#define lbwatkow 5
#define N 100

int Tab[N];
int TabMin[lbwatkow];

void Wypelnij();
void MinWatek(int poczatek, int koniec, int nr_watku);
void Szukajmin();
void znajdzmin();

int main()
{
	Wypelnij();
	Szukajmin();
	getchar();
}

void Wypelnij()
{
	for (int i = 0; i < N; ++i)
		Tab[i] = rand() % 100 - 50;
}

void MinWatek(int pocz, int kon, int nr_watku)
{
	int min = Tab[pocz];
	for (int i = 0; i < kon; ++i)
	{
		if (Tab[i] < min)
			min = Tab[i];
	}
	TabMin[nr_watku] = min;
}
void Szukajmin()
{
	int Podzialy = N / lbwatkow;
	thread TabWatkow[lbwatkow];
	thread *wskTab = TabWatkow;
	for (int i = 0; i < lbwatkow; ++wskTab, ++i)
	{
		wskTab = new thread(MinWatek, i*Podzialy, (i + 1)*Podzialy, i); // tworzone nowe watki wraz z podzialami do szukania
	}
	znajdzmin();
}
void znajdzmin() // szukanie minimum w tablicy min. ktore znalazly watki
{
	int min = TabMin[0];
	for (int i = 1; i < N; ++i)
	{
		if (TabMin[i] < min)
			min = TabMin[i];
	}
	cout << "Minimum = " << min << endl;
} 
spartanPAGE
  • Rejestracja:około 12 lat
  • Ostatnio:około 13 godzin
2

Po ludzku?
Użyj boost::thread_group group; wraz z group.join_all();

Po mniej ludzku:
Skoro i tak musisz poczekać na >wszystkie< wątki, to nie interesuje Cie to, że jesteś blokowany.
Tak więc zwykła pętelka wystarczy.

Kopiuj
for(auto &thread : threads)
    thread.join();
0

Troche nie bardzo rozumiem. Dołożyłem pętle za pętlą która tworzy wątki i nic to nie pomogło. Próbowałem równiez zaraz po utworzeniu wątku zrobić TabWatkow[i].join(); ale tak samo nic..

twonek
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
1
Zimny Młot napisał(a):

Troche nie bardzo rozumiem. Dołożyłem pętle za pętlą która tworzy wątki i nic to nie pomogło. Próbowałem równiez zaraz po utworzeniu wątku zrobić TabWatkow[i].join(); ale tak samo nic..

No to zobaczmy:

Kopiuj
thread TabWatkow[lbwatkow];

Tworzy 5 obiektów nie reprezentujących żadnych wątków. To wyjaśnia:

Próbowałem równiez zaraz po utworzeniu wątku zrobić TabWatkow[i].join(); ale tak samo nic

Kopiuj
thread *wskTab = TabWatkow;

wskTab wskazuje na początek tablicy TabWatkow.

Kopiuj
for (int i = 0; i < lbwatkow; ++wskTab, ++i)
{
    wskTab = new thread(MinWatek, i*Podzialy, (i + 1)*Podzialy, i); // tworzone nowe watki wraz z podzialami do szukania
}

w każdym obiegu pętli wskTab wskazuje na nowy adres, który nie ma nic wspólnego z TabWatkow, więc jeśli potem próbujesz robić join() za pomocą TabWatkow, to raczej marne szanse, że się uda.

0

Ok rozumiem to, że w kazdym obiegu pętli wskTab wskazuje na nowy adres, ale dlaczego nie moge w każdym obiegu podłączyć aktualnie tworzonego wątku (po new) poprzez join().
Probowałem jeszcze po stworzeniu wszystkich wątków (za pętlą) jeszcze raz przejść i podłączyć wszystkie poprzez:

Kopiuj
for(auto &thread : TabWatkow)
    thread.join();

Ale również nie udało się.

0

Czy takie rozwiązanie jest poprawne? Po prostu w pętli dodałem wskTab->join();

Kopiuj
#include <iostream>
#include <thread>
#include <ctime>
using namespace std;
#define lbwatkow 5
#define N 1000
int Tab[N];
int TabMin[lbwatkow];

void Wypelnij();
void MinWatek(int poczatek, int koniec, int nr_watku);
void Szukajmin();
void znajdzmin();

int main()
{
	Wypelnij();
	Szukajmin();
	getchar();
}

void Wypelnij()
{
	for (int i = 0; i < N; ++i)
		Tab[i] = rand() % 100 - 50;
}

void MinWatek(int pocz, int kon, int nr_watku)
{
	int min = Tab[pocz];
	for (int i = 0; i < kon; ++i)
	{
		if (Tab[i] < min)
			min = Tab[i];
	}
	TabMin[nr_watku] = min;
	cout << "Watek numer: " << nr_watku << " znalazl minimum i zakonczyl prace. " << min << endl;
}
void Szukajmin()
{
	int Podzialy = N / lbwatkow;
	thread TabWatkow[lbwatkow];
	thread *wskTab = TabWatkow;
	for (int i = 0; i < lbwatkow; ++wskTab, ++i)
	{
		wskTab = new thread(MinWatek, i*Podzialy, (i + 1)*Podzialy, i); // tworzone nowe watki wraz z podzialami do szukania
		wskTab->join();
	}
	znajdzmin();

}
void znajdzmin() // szukanie minimum w tablicy min. ktore znalazly watki
{
	int min = TabMin[0];
	for (int i = 1; i < N; ++i)
	{
		if (TabMin[i] < min)
			min = TabMin[i];
	}
	cout <<endl << "===== Minimum = " << min << endl;
}
twonek
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
0
Zimny Młot napisał(a):

Probowałem jeszcze po stworzeniu wszystkich wątków (za pętlą) jeszcze raz przejść i podłączyć wszystkie poprzez:

Kopiuj
for(auto &thread : TabWatkow)
    thread.join();

Ale również nie udało się.

twonek napisał(a):

w każdym obiegu pętli wskTab wskazuje na nowy adres, który nie ma nic wspólnego z TabWatkow, więc jeśli potem próbujesz robić join() za pomocą TabWatkow, to raczej marne szanse, że się uda.

Po co w ogóle bawisz się ohydnym wskaźnikiem skoro i tak masz statyczną tablicę?

Kopiuj
thread TabWatkow[ILE_WATKOW];
for (int i = 0; i < ILE_WATKOW; ++i)
{
	TabWatkow[i] = thread(MinWatek, i*Podzialy, (i + 1)*Podzialy, i);
	TabWatkow[i].join();
}
spartanPAGE
Przy statycznej tablicy przejdzie foreach
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
3

Zastosowanie join w pętli czyni użycie wątków kompletnie bezsensownym.

edytowany 1x, ostatnio: _0x666_
spartanPAGE
Mea culpa, widzę, że ma się to bezpośrednio do kodu OP, który faktycznie machnął głupotę.
vpiotr
@spartanPAGE: nie masz racji, jest zupełnie inaczej: http://tinyurl.com/oxj865w
vpiotr
no i teraz cały żart poszedł w p...inezki.
spartanPAGE
Zdążyłem się uśmiać :)
0
0x666 napisał(a):

Zastosowanie join w pętli czyni użycie wątków kompletnie bezsensownym.

Dlaczego?

Dzięki za pomoc dla kolegi wyżej, już chyba załapałem o co chodziło :)

twonek
Przy każdym join główny wątek będzie czekał na zakończenie tego nowo utworzonego wątku.
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
1

Dlatego, że wszystko, pomimo użycia kilku wątków, i tak wykonuje się sekwencyjnie. Tworzysz wątek, czekasz aż się wykona, po czym znowu tworzysz wątek dla następnego przedziału i czekasz, itd. Równie dobrze mógłbyś wywalić te wątki, a w pętli od razu wywoływać MinWatek. Takie rozwiązanie byłoby szybsze ;)

Odpal ILE_WATKOW wątków w jednej pętli, a w drugiej czekaj na ich zakończenie.

0

Czekać poprzez join czy jest jakaś metoda która sprwadza, że wątek się zakończył?
Dzięki za informacje, faktycznie wszystko wykonuje się po kolei więc traci to sens.

0

Zmieniłem na coś takiego:

Kopiuj
	for (int i = 0; i < lbwatkow;  ++i)
	{
		TabWatkow[i] = thread(MinWatek, i*Podzialy, (i + 1)*Podzialy, i); // tworzone nowe watki wraz z podzialami do szukania
		//TabWatkow[i].join();
		/*wskTab->join();*/
	}
	for (int i = 0; i < lbwatkow; ++i)
	{
		TabWatkow[i].join();
	}

i wydaje się działać tak jak powinno :)

spartanPAGE
yep, o tym dokładnie mówił mój post.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.