Zaawansowane: Czy uzywac Synchronize (watki)

Zaawansowane: Czy uzywac Synchronize (watki)
EgonOlsen
  • Rejestracja: dni
  • Ostatnio: dni
0
HoldenCaulfield napisał(a)
EgonOlsen napisał(a)

Nie musi, jesli mamy watek wbudowany w obiekt to kazdy taki obiekt moze (a nawet powinien) miec swoj critical section, najprosciej zdziecziczyc obiekt z critical section i juz.

Jesli do tej samej zmiennej globalnej bedzie mialo dostep kilka watkow, to kazdy z tych watkow musi korzystac z tego samego TCriticalSection, inaczej to mija sie z celem.

Racja, jednak ozywanie zmiennych globalnych w c++ wydaje mi sie herezja.

b0bik
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1114
0

Witam

Przeczytałem dzisiaj z grubsza ten "wątek" i wrzucę swoje 3 grosze. Otóż, zawsze, ale to bezwzględnie zawsze trzeba mieć na uwadze możliwość "jednoczesnego" dostępu do zmiennych gobalnych przy stosowaniu wątków. Dlatego też zawsze trzeba stosować mechanizmy takie jak sekcje krytyczne, czy synchronizacje. To że Tobie się wydaje, że to nie był problem - masz racje tylko Ci się wydaje. Czasem można sprawę rozwiązać przez threadvar zamiast var, ale działa to wolno, a poza tym w Twoim przypadku nie jest to chyba rozwiązanie. Jeśli stwierdziłeś, że kolejne wątki odpalają Ci się zanim skończy się poprzedni, to jak najbardziej <ort>równierz </ort>może to być przyczyną przepełnienia stosu - ale taka sytuacja w poprawnie zprojektowanej aplikacji nie powinna mieć miejsca. Jeśil wybierzesz rozwiązanie pt. "Licznik uruchomionych wątków" to, też powinieneś zastosować sekcje krytyczne.

Żeby od razu nie robić burzy w szklance wody, piszę tego posta nie <ort>po to </ort>abyś się poczuł obrażony/urażony, tylko po to żebyś się przekonał do właściwego stylu prazy z wątkami. Poszukaj sobie na interncie to sam się przekonasz, że wiele osób które Ci tutaj odpowiedziały mają racje. Jak masz możliwość, to przeczytaj sobie Vademecum <ort>Profesionalisty </ort>do D4. Tam (chyba w 2 tomie), wyjaśnione jest po co są sekcje i Synchronize w bardzo przystępny sposób.

Programowanie z użyciem wątków, ma swoje wady i zalety. Jedną z wad jest fakt, że trudno wychwytuje się błędy, choćby przy użyciu debugger'a. Kolejność wykonywania wątków (zarówno głównego jak i podrzędnych), nie jest do przewidzenia. Jedyna pewna rzecz jest taka, że system przydzieli czas procesora dla każdego z nich, ale co w tym czasie Twój wątek zdąży, i w jakim momencie system go wstrzyma to tego nawet najstarsi górale nie wiedzą.

P.S. bardzo mnie ciekawi w jaki sposób zapewniasz uruchamianie tych wątków co te 10ms ; )

Pozdrawiam

NI
  • Rejestracja: dni
  • Ostatnio: dni
0

hehe, nie mam ochoty sie <ort>klucic </ort>problem rozwiazalem i chodzi to bez problemu.

Bardzo ąłtwo sobie sprawdzic dostep z watku do zmiennych globalnych powodujac kolizje sam wyprobuj tylko utrzymaj stos na poziomie 10 k powyzej ci system zamknei aplikacje...:)

synchronize mutexu rozwiazanie dla opornych sa lepsze <ort>inowacyjne </ort>metody, to co twierdzisz to absurd poczytaj sobie o wątkach i zmiennych globalnych oraz dostępie do nich :)
tylko nie na forum bo tu róznie ludzie sadza czesto wypowiadajac sie <ort>niemajac </ort>pojecia o czym mowa uslysza gdzies ze nie mozna i na tym sie skonczy ja przeprowadizlem testy i udowodnilem ze sekcje krytyczne czy kolejkwoanie nie ma sensu w wypadku zmiennych globalnych, wyzej wymienione maja sens w przyadku wykorzytywania <ort>komponetow </ort>wizualnych

pozdrawiam.
aha dodam ze tacy z niektorych wszechwiedzacy a niewiedza iz nie mozna podtrzymywać procesu w SOCKET czy <ort>jakich kolwiek</ort> innych <ort>polonczeniach</ort>, dlatego sadze ze <ort>NIE MA </ort>o czym rozmwiac.

pozdraiwam

EgonOlsen
  • Rejestracja: dni
  • Ostatnio: dni
0
b0bik napisał(a)

Kolejność wykonywania wątków (zarówno głównego jak i podrzędnych), nie jest do przewidzenia. Jedyna pewna rzecz jest taka, że system przydzieli czas procesora dla każdego z nich, ale co w tym czasie Twój wątek zdąży, i w jakim momencie system go wstrzyma to tego nawet najstarsi górale nie wiedzą.

Mozna nad tym troche zapanowac ustawiajac priorytety watkow.

NI
  • Rejestracja: dni
  • Ostatnio: dni
0
EgonOlsen napisał(a)

Mozna nad tym troche zapanowac ustawiajac priorytety watkow.

ustawiaj tylko zrób wcześniej kopie aktualnych niezapisanych danych bo gwarantuje ci ze bez dodatkowych ograniczeń system ci sie powiesi ;) aha zależy tez od częstotliwości występowania kolejnych wątków i czym ona jest warunkowana...

nie ma też problemu by "zważyć" ile pamięci zajmuje konkretny wątek, ale uważam ze to bardziej przeciąża nic pomaga...

pozdrawiam :)

  • Rejestracja: dni
  • Ostatnio: dni
0

Jest jeszcze inny problem "narzucony czas obliczeń". Wątkom można nakazać kolejność wykonywania; z tym nie ma problemu. Niestety problemem jest wykonanie zadania podzielonego na n procesorów (np 3) przy priorytecie normalny aby zawsze dal czas obliczeń 30 sekund (+/- do 4 sekund) . Często zdarza mi sie ze uruchamia się przy drugim przyciśnięciu (czasem dopiero przy trzecim) zadanie podzielone na tablice wątków liczy aż 60 ( 2 razy lub więcej) kończy watek jeden z trzech (niekoniecznie zerowy) a reszta "wisi". Na wieki sie nie zawiesza dochodzi do końca. Kiedy dałem priorytet timecritical ( i REALTIME_PRIORITY_CLASS jednocześnie) to zawsze daje czas obliczeń 30 sekund (+/- 3 sek). Nie wiem jak się ma tez związek klasy priorytetowej procesu i priorytet względny ( w książce mowa o wypadkowej tych priorytetów). Dlaczego tylko przy pierwszym uruchomieniu tablicy wątków watki zakończą jednocześnie?

ŁF
  • Rejestracja: dni
  • Ostatnio: dni
0

utwórz tyle wątków, ile jest procesorów, i każdemu z nich przypisz inną koligację (affinity mask), w ten sposób każdy będzie pracował tylko na jednym procesorze i będzie wyciągał z niego 100%; windows często ma problemy z obciążeniem wszystkich rdzeni na 100% bez specjalnych zabiegów programistycznych.

tak poza tym - przyciśnięciu kogo? czego? papierów przyciskiem? uprowadzonego sklepikarza, który nie chciał płacić haraczu?
synchronizujesz wątki miedzy sobą? pokaż reprezentatywny kawałek kodu.
wątki nie kończą się jednocześnie. praktycznie nigdy. różnice w czasie wykonania zależą od tego, który wątek co robi i którym wątkom system przypisał które rdzenie. jeśli dwa wątki biegają na tym samym rdzeniu, a trzeci na drugim, rdzeń #3 stygnie, a wątek #3 kończy się pierwszy.

  • Rejestracja: dni
  • Ostatnio: dni
0
Kopiuj
function WaitForMultipleThreads(const ThrArr : array of TexThread;TimeOutVal : DWORD) : Word;
var
  Hndls : TWOHandleArray;
  I     : Integer;
  //hndle1:array of thandle;
begin
 for I := 0 to High(ThrArr) do
    Hndls[I] := ThrArr[I].Handle;
  Result := WaitForMultipleObjects(High(ThrArr) + 1, @Hndls, True, TimeOutVal)
end;

procedure TForm1.Button6Click(Sender: TObject);
var
wresult:dword;
systeminfo:Tsysteminfo;
nproc:integer;
cpus:integer;//wystarczy byte
susel:boolean;
i,stczas,konczas:integer;
begin
//Pozostale zmienne sa globalne
// TExthread.execute w sekcji krytycznej
// przepisuje zmienne globalne
//CriticalSection: TRTLCriticalSection; 
//zmienne zostaly ustawione w innej procedurze jako globalne 
GetSystemInfo(SystemInfo);
if checkbox15.checked then begin
nproc:=1;
end else begin
nproc:=systeminfo.numberOfProcessors;
end;
susel:=False;
setlength(testarraythread1[cpus].mtx,cache+1);

for cpus:=0 to nproc-1 do begin
try

if cpus=0 then begin
testarraythread1[cpus]:=TExthread.Create(1, taskrun1[cpus+1],cpus,susel);
setlength(testarraythread1[cpus].mtx,cache+1);
for i:=1 to cache6 do begin
testarraythread1[cpus].mtx[i]:=matrixselected2[i];//kopiowanie tablic "unikanie kolizji" VCL
end;
end
else begin
testarraythread1[cpus]:=TExthread.Create(taskrun1[cpus]+1,taskrun1[cpus+1],cpus, susel);

setlength(testarraythread1[cpus].mtx,cache+1);
//przepisanie tablicy kompilator nie protestuje 
for i:=1 to cache6 do begin
testarraythread1[cpus].mtx[i]:=matrixselected2[i];
end;
end;
mask:=trunc(Ldexp(1,cpus));  // kazdy watek na osobnym rdzeniu
// Porada z forum 
testarraythread1[cpus].SetAffinity(mask);
testarraythread1[cpus].Priority:=tpnormal;
//testarraythread1[cpus].Priority:=tptimecritical;//tpnormal;
testarraythread1[cpus].setpriority(NORMAL_PRIORITY_CLASS);
//testarraythread1[cpus].setpriority(REALTIME_PRIORITY_CLASS);//NORMAL_PRIORITY_CLASS);
Application.ProcessMessages;
except
Showmessage('System is busy...Try again');
break;
end;
end;
InitializeCriticalSection(CriticalSection);
Stczas := GetTickCount;
for cpus:=0 to nproc-1 do begin
try
testarraythread1[cpus].Resume; //start po zdefiniowaniowaniu priorytetu i maski
Application.ProcessMessages;
except
Showmessage('Error');
break;
end;
end;
wresult:=WaitForMultipleThreads(testarraythread1,INFINITE); //tablica watkow sztucznie statyczna
konczas := GetTickCount;
while (Assigned(testarraythread1)) do
begin
testarraythread1:=nil;
Application.ProcessMessages;
end;
DeleteCriticalSection(CriticalSection);
label1.caption:=inttostr(konczas-stczas);
end;

Nie wiem czy sekcje krytyczna można usunąć po zwolnieniu wątku? Czy kolejność ma aż takie znaczenie?
Dziękuję ŁP za odpowiedz.
PS.

  • Rejestracja: dni
  • Ostatnio: dni
0

Panie ŁF nie chce zaśmiecać forum bo kod jest dłuzszy. Maskowanie wątku na rdzeń poprzez mask:=trunc(Ldexp(1,cpus)); nie pomogło przestawię sekcję krytyczną
DeleteCriticalSection(CriticalSection);
while (Assigned(testarraythread1)) do
begin
testarraythread1:=nil;
Application.ProcessMessages;
end;

Wiadomo ze parę procent obliczeń dla wątków może się różnić, ale nie 60 lub 80 % troche to przesada.
Dla mnie to gryzący problem nie poruszany nigdzie. Dziękuję.

ŁF
  • Rejestracja: dni
  • Ostatnio: dni
0

o rany, formatuj kod, bo na ten nie chce się patrzeć.
co mi po sposobie, w jaki wywołujesz wątki, kiedy to wątki działają dziwnie?

btw:

Kopiuj
for cpus:=0 to nproc-1 do begin
testarraythread1[cpus]:=TExthread.Create(1, taskrun1[cpus+1],cpus,susel);

a potem

Kopiuj
for i:=1 to cache6 do begin
testarraythread1[cpus].mtx[i]:=matrixselected2[i];
end;

jak to ma działać, jeśli cache6 != nproc-1?
jeśli kod wątków wygląda podobnie, to masz pewnie jakiś banalny błąd.
dziwnie wygląda tworzenie sekcji krytycznej po utworzeniu wątków. działa, bo wątki są zapauzowane - ale stoją tuż przed krawędzią przepaści. do tego synchronizacja wątków przez skopiowanie tablicy, na której pracują też budzi wątpliwości.

nie mogę już dłużej patrzeć na ten kod. sformatuj go!

  • Rejestracja: dni
  • Ostatnio: dni
0

ŁF miałeś rację błąd tkwi w sekcji krytycznej. Dla oszczędności wykorzystuję każdy bit tablicy (boolean niestety zajmuje cały bajt chyba że czegoś nie wiem.Moze są tablice wykorzystujące bit nie bajt tego typu.) W tablicy wątków podzielilem obszar na ilość procesorów w systemie. Mając tablice globalną matrixselected i tablice lokalne mtx liczone na oddzielnych rdzeniach następuje kolizja w pierwszym i ostatnim bajcie tablic lokalnych podczas scalania wyników.(akurat 4 bity zapisywane są na rożnych rdzeniach w to samo miejsce w tablicy globalnej) Piewszy bajt tablicy lokalnej wątku dot. rdzenia 0 i ostatni bajt tablicy lokalnej wątku rdzenia 2 (w tym przypadku ostatniego) jest wolny od wszelakich kolizji. Nie wiem może mutexy lub semafory załatwią sprawę. Kolizji jest tyle ile rdzeni-1 .

  • Rejestracja: dni
  • Ostatnio: dni
0

Już myślałem że problem jest z głowy, lecz nie do końca. Zadanie jest takie że uruchamia się tablicę wątków (tyle ile rdzeni wiec dynamicznie trzeba to utworzyć). dane się pobiera z globalnej tablicy dostępnej dla wszystkich wątków a wyniki wpisuje do tablicy koncowej ( scalanie wyników). Kazdy wątek z tablicy thread[nr_proc] ma zmienne publiczne. Sprawdzilem to: Wątki nie ingerują miedzy sobą czyli zmienna globalna zadeklarowana w tablicy wątków jest "każda dla siebie". Niestety kod procedury mają wspólny umieszczony Texthread.execute. Dzieląc tą procedurę na sekcje krytyczne podział odczyt/obliczenia/zapis wywoływane są pokolei od rdzenia 0 do 2 ( akurat miałem sprawdzic na 3 rdzeniach).
Jak uruchomić procesy równolegle? Specjalnie zadanie podzielilem na tak, aby kazdy rdzen miał tyle samo "pracy" czyli mniej więcej podobny czas zakończenia podzadania (za każdym razem czas obliczen niemal identyczny +/- 10% ). Czekam na odpowiedź.
PS. W ksiązce wg ktorej robilem jest błąd i jestem tego swiadomy. Chodzi mi o przyklad ktory na 100% bedzie działał i rozwiaze ten problem na wieki. Amen.

  • Rejestracja: dni
  • Ostatnio: dni
0

Jest tak jak wąż z dwoma głowami. Znalazłem na sieci coś takiego:
"każdy proces ma przydzielony odrębny obszar pamięci operacyjnej
grupa równorzędnych wątków współdzieli tą samą przestrzeń adresową, kod i zasoby systemu operacyjnego"
HMMM Tablica procesów rozwiązaniem? Być może. Czekam na mądrą odpowiedź. ( Wątek i proces to nie są równorzędne pojęcia kolejny błąd na który się natknąłem).

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.