Mam napisać program wielowątkowy, w sumie już go napisałem jednak pojawia się problem. Dzielę dane na porcje. Następnie je przetwarzam i zapisuje wyniki do wspólnej tabeli z wynikami. Jak wygląda od środka taki zapis? Ponieważ wyniki dla 1 wątku, 2,3 itd się różnią. Nie jest tak że jeśli dwa wątki na raz chcą wykonać tablica[5]++ to jeden z nich nie dostaje dostępu ?
Jednoczesne operowanie kilku wątków na jednej tablicy może mieć nieciekawe skutki. Inne platformy mają jakieś mechanizmy rywalizacji wątków, więc pewnie ma je i .NET. Jednak żeby lepiej nad tym zapanować użyj Mutexów albo innych Monitorów:
Aktualnie mam tak ze tworze listę tablic do których kazdy wątek będzie zapisywał wyniki ze swojej porcji danych. Do watku przesyłam dane i numer watku tak żeby wiedzial do której tablicy w liście sie odwołać a na końcu lacze wyniki ze wszystkich tablic. Sprawdzałem i działa jak należy.
Jeśli to ma być zwykła inkrementacja wartości, to należy używać tzw. atomiców. Tego typu funkcje mają zazwyczaj w nazwie słówko “interlocked” i ich charakterystyczną cechą jest właśnie odporność na hazardy. Pewnie w .NET też coś takiego jest. Jeżeli natomiast wątki ciągle wymieniają się danymi, tzn. każdy wątek zapisuje i odczutuje dowolne elementy całej tablicy, to musisz to przemyśleć. Można zrobić tak, że na czas zapisu/odczytu lockujesz tę tablicę (słówko kluczowe “lock”) ale może się okazać, że program będzie się wtedy wykonywał dłużej niż jego jednowątkowy odpowiednik.
Bardzo “enigmatycznie” przedstawiasz swój problem. Zaprezentuj fragment kodu źródłowego, w którym - według Ciebie - tkwił błąd, a wtedy na pewno znajdziemy wspólny język.
Bo każdy kto programował wielowątkowo wie o co chodzi
int ilosc=0;
int ilosc_watkow=500;
List watki = new List()
void funkcja_watku()
{
for(int i=0;i<10000;i++)
ilosc++;
}
void funkcja_start()
{
for(int i=0;i
{
watki.Add(new Thread(funkcja_watku));
watki[i].Start();
}
}
Po wykonaniu się tego kodu ilość powinna być 5 000 000 a jest ~4 800 000. Ktoś wyżej dawał ciekawy link. Ja póki co mam zrobione w sposób prosty gdzie każdy wątek zapisuje wyniki do swojej listy i na końcu listy są łączone.
No widzisz, takie operacje jak ilosc++ w środowisku wielowątkowym powinieneś wykonywać z goła inaczej. Masz bardzo wiele możliwości poprawienia swojego kodu. Niektóre z dostępnych możliwości to:
wykorzystaj słowo kluczowe lock i wskaż wspólny dla wszystkich wątków obiekt (readonly object obj = new object()), do którego dostęp będziesz każdorazowo blokował w danym wątku przed wykonaniem inkrementacji na zmiennej “ilosc”.
wykorzystaj klasę Interlocked i metodę Increment
wykorzystaj słowo kluczowe volatile na globalnej zmiennej “ilosc”
To są bardzo podstawowe mechanizmy, a ułatwią Tobie znacznie pracę.
Z drugiej strony, kiedy wyświetlasz wartość zmiennej “ilosc”? Skąd wiesz, że wszystkie wątki zakończyły pracę? Prawdopodobnie wyświetlasz zawartość zmiennej w chwili kiedy jest ona jeszcze przedmiotem pracy w tle… -> poczytaj o Thread.Join i podobnych zagadnieniach.
Mam też bardzo łopatologiczny sposób na to Wiadomo każdy się uczy i kombinuje. Ja wykombinowałem tak że znowu każdy wątek zapisuje true że się skończył. Dodatkowy wątek ma pętle While(true) i sprawa czy każdy wątek zapisał true. Jeśli tak to dopiero wyświetlam. Ale wiadomo z wątkami miałem do czynienia ale tylko w taki sposób że jest jeden wątek tak aby forma nie sprawiała wrażenia że się zawiesiła. Teraz na studiach weszło programowanie współbieżne więc muszę się bardziej zagłębić w wątki.
Brawo, dajesz sobie radę, ale taką samą informację uzyskasz z pola Thread.IsAlive (żyjesz? jeżeli nie, to albo zakończyłeś obliczenia, albo anulowałem twoją pracę)
Jak zwykle, najlepszym źródłem wiedzy jest MSDN, ale bardzo dobrą lekturą jest także:
Można i tak, ale z doświadczenia powiem Ci, że bardziej opłaca się nie kombinować, tylko przeczytać jak coś działa i zacząć nową wiedzę stosować w praktyce.