Autor Wątek: wątki  (Przeczytany 1513 razy)

Offline kapustman

  • Użytkownik

# Listopad 12, 2016, 23:00:08
Szybkie pytanie, mam program wielowątkowy i jedną tablicę na dane wyjściowe. Dzielę tę pamięć na całkowicie niezależne od siebie regiony, do których każdy wątek tylko pisze. Pamięć wynikowa jest czytana dopiero po zakończeniu pracy przez wątki.

#include <vector>
#include <thread>

void func(int i, int* ret)
{
      for(int k = i; k < i+1000; ++k)
            ret[k+5000] = k;
}

void foo()
{
      int mem[10000];
      std::vector<std::thread> workers;
     
      for(int i = -5000; i < 6000; i += 1000)
            workers.push_back(std::thread(func, i, mem));

      for(auto& i : workers)
            i.join();
     
      //i tu następuje odczyt z tablicy mem
}

Czy w taki kod będzie działał tak jak chcę, czy też jest ryzyko data race?
« Ostatnia zmiana: Listopad 12, 2016, 23:48:11 wysłana przez kapustman »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Durson

  • Użytkownik

  • +1
# Listopad 12, 2016, 23:36:43
Cześć, najważniejsza spawa, tę pamięć.
Uff, teraz można przejść do rzeczy. Tak, jeśli podzielisz tablicę na podtablice i każdą przydzielisz osobnemu wątkowi to nie ma żadnego problemu. Musisz tylko ofc. poczekać aż wszystkie się zakończą, co robisz.

Problemem natury technicznej jest to, że podajesz do func wartości [-5000, ..., 5000], no i func jeździ przed tablicą, ale domniemywam, że to tylko na kolanie napisany przykład.

W ogólności problem pojawia się tylko jak dwa wątki piszą do tej samej pamięci, albo jeden pisze a drugi w tym samym czasie czyta. Mogą czytać wspólną pamięć, nawet bardziej skomplikowane struktury danych pisze się tak, aby operacje odczytywania były thread-safe
http://stackoverflow.com/questions/1846186/thread-safety-of-stdmap-for-read-only-operations

Co ciekawe, można także usiągnąć thread-safe nieblokujący zapis za pomocą np. operacji atomowych, czy ogólniej lock-free programming i napisać w ten sposób licznik, stos, kolejkę itd.
Pozdr
« Ostatnia zmiana: Listopad 12, 2016, 23:43:16 wysłana przez Durson »

Offline kapustman

  • Użytkownik

# Listopad 12, 2016, 23:52:24
Tak, to tylko pisany na kolanie przykład. Dzięki za odpowiedź!

Offline .c41x

  • Użytkownik
    • homepage

# Listopad 13, 2016, 15:06:23
Jeśli wątki pracują na oddzielnych blokach pamięci to oczywiście nie będzie tu data-race. Natomiast taki przypadek może prowadzić do innego problemu wydajnościowego opisywanego jako false-sharing. W skrócie chodzi o to, że CPU pobiera pamięć do cache blokami i jeśli kilka wątków czyta/zapisuje do tego samego bloku to cały blok jest unieważniany i musi nastąpić synchronizacja - co w ogóle skreśla rozbijanie takiego kodu na wątki. To jest bardzo trudny problem do rozwiązania, bo to jest kwestia sprzętowa, nie związana z językiem samym w sobie. Kluczem jest profiling i odpowiednie dobranie rozmiaru na który dzielisz tablicę - od razu tu widzę, że 1000 to nie jest dobra liczba.

Offline MrKaktus

  • Użytkownik

# Listopad 13, 2016, 18:16:04
Po prostu trzeba podzielic dane na bloki o rozmiarze bedacym wielokrotnoscia cache line size. Obecnie to 64 bajty dla Intela i chyba 32 dla ARM.

Offline lethern

  • Użytkownik

# Listopad 14, 2016, 12:17:59
Nie wiem czy wystarczy przekazywanie bloków "podzielnych przez 64B" żeby rozwiązać opisany wyżej problem, jeśli język jakoś gwarantuje, że początek tablicy zawsze będzie wyrównany "do początku linii cache"  (sorry za chłopski język)
(przy sizeof(int)==4 mamy w linii cache 16 komórek tablicy, czyli np. 1008 w miejsce 1000 dla indeksów)
wydaje się, że inną drogą dla 100% gwarancji to dodać 64B pustych komórek między danymi jednego i kolejnego wątku

PS Twój sposób zapisu indeksu i jego górnej granicy jest wręcz smutny, nie można było to jakoś po ludzku, bez ujemnych wartości, +1000, i innych?
PPS tak mi się przypomniało, w podejściu np. MapReduce (googlowym) mieliby pewnie osobną tablicę per obliczenia równoległe (choć nich dane latają między różnymi maszynami, nie jak tu wątkami)
« Ostatnia zmiana: Listopad 14, 2016, 12:25:15 wysłana przez lethern »

Offline ArekBal

  • Użytkownik

# Listopad 17, 2016, 00:10:20
Cytuj
choć nich dane latają między różnymi maszynami, nie jak tu wątkami
Nie ważne jaka skala... "data locality" zawsze ważne. Jeśli możesz coś policzyć na jednej maszynie w ramce czasu, to zrób to na jednej maszynie. Nawet jak masz klastry, to lepiej unikać skakania po maszynach, jeśli się da.