[ FranjoZG @ 07.02.2017. 11:40 ] @
Ako netko ima malo vremena i volje...
Imam program u D2007 koji radi OK, a sinhronizira podatse local.FB -> web.MySQL. Nekliko različitih vrsta sinronizacija koje rade u zasebnim thread-ovima.

Sada to pokušavam napraviti u XE7 sa task-ovima. Konekcije na lokanu bazu i na onu na webu se rad s TFDConnection. Svaki task kreira svoju konekciju i kontrole za pristup podacima.

Ovo je primjer onoga što pokušavam:
Code:

procedure TfmMain.Button1Click(Sender: TObject);
begin
   tt[1] := TTask.Create (procedure () 
       var a1: tMyThreadAdresar;  // ovo i Create sam pokušao staviti i van TTask-a
   begin 
         a1 := tMyThreadAdresar.Create(fmMain);
         a1.MainProcedure := CountActivThread; // proc u main formi, iz a1.Execute se poziva s parametrom integer koji se zbraja na var UKUPNO. Na početku procedure +1, a na kraju -1. 
                                                               // Procedura pri parametru -1 provjerava da li je UKUPNO = 0, pa ako je ispiše "Gotovo"
         a1.Log := self.Log;  // TListView - prikazuje log posla. U Threadu se koristi Synchronize za upis u ListView.
         a1.Params := Param; // Param je objekt koji sadrži parametre za spajanje na baze itd. definiran u main thread-u, ne mijenjam ga u objektu "a1" samo čitam
         a1.Name := 'a1';
         a1.Execute;     // methoda koja obavlja sinhronizaciju
   end); 
   
   // slijede još 3 ista, s tim da su a2, a3 i a4 varijable
   tt[2] := ...
   tt[3] := ..
   tt[3] := ..

   tt[1].Start; 
   tt[2].Start;
   tt[3].Start;
   tt[4].Start;
   while not TTask.WaitForAll(tt, 1) do begin
     CheckSynchronize(0);
     Application.MainForm.Update;
     Application.ProcessMessages;
  end;
end;


u "a1" se:
- otviri FB baza i MySQL baza, ptrotrči kroz jednu od tablica na webu i u FB.
- kreira progressbar koji se prikazuje na main formi i pokazuje

Gdje griješim? Program javlja greške od Access Violation... na dalje, kako kad. Ponekad s izvrti do pola pa zablokira, ponekad završi ali kod gašenja ostane "visjeti" u task manager-u.

[ salvaric @ 07.02.2017. 12:07 ] @
Da li si pokušao da dodaš:
Code:
...
a1.Name := 'a1';
a1.Execute;     // methoda koja obavlja sinhronizaciju
a1.WaitFor;   // da sačeka izvršenje

Možda ti se kose thread-ovi prilikom upisa podataka u istu komponentu npr (TListView).
[ savkic @ 07.02.2017. 12:21 ] @
Pogledaj http://docwiki.embarcadero.com...n/Multithreading_%28FireDAC%29, mozda neki od uslova nisu uradjeni.

> Gdje griješim? Program javlja greške od Access Violation... na dalje, kako kad. Ponekad s izvrti do pola pa zablokira,
> ponekad završi ali kod gašenja ostane "visjeti" u task manager-u.

AV je jedan od nacina kako se manifestuje upotreba nekog resursa iz vise threadova, mada mozda je problem na nekom drugom mestu, tipa ako nesto radis direktno sa memorijom ili pristupas nekoj od VCL kontrola van synchronize.
[ FranjoZG @ 07.02.2017. 13:44 ] @
Upis u komponentu u main thread-u radim sa Synchronize.
Svi thread-ovi pristupaju istoj lokalnoj i istoj web bazi, ali u svakom koristim njegove kontrole koje u njemu i kreiram.

Zajedničko sa main thredom je:
TListView
file u koji se upisuje log
Param = objekt moje klase, ja ju složio, koja pamti sve parametre

file za log kod svakog upisa u njega otvaram i zatvaram unutar svakog thread-a isto tako u Synchronize.

Još pitanje:
razlika, prednosti, mane korištenja TTaska na načina kako ga koristim i klase:
Code:

  tnt=class(tthread)
  
  end;


tražio sam po net-u, ali nisam baš našao nešto pametno, možda iz vađeg iskustva?
[ savkic @ 07.02.2017. 14:12 ] @
> Svi thread-ovi pristupaju istoj lokalnoj i istoj web bazi, ali u svakom koristim njegove kontrole koje u njemu i kreiram.

Da li imas FDManager.Active := True pre kreiranja taskova?

> Još pitanje: razlika, prednosti, mane korištenja TTaska na načina kako ga koristim i klase:
> tnt=class(tthread)

Ovo nisam shvatio?
[ salvaric @ 07.02.2017. 14:21 ] @
Citat:
file za log kod svakog upisa u njega otvaram i zatvaram unutar svakog thread-a isto tako u Synchronize.


Možda ti u istom momentu dva ili više thread-ova pokušava da otvori log fajl, u tom slučaju bit će dostupan samo za prvog, iako su to delići sekune. Mislim da sam i ja sa tim imao ranije sličan problem, pokušaj da okidaš thread-ove pojedinačno, jedan za drugim pa vidi dal će ti prijaviti grešku.
[ FranjoZG @ 07.02.2017. 16:20 ] @
Za log file sam i sam pomislio, pokušat ću to riješiti drugačije.

Savkić, na žalost ne. Može ukratko? (:

Idem doma na klopu (konačno). Sutra je pametnije...
[ savkic @ 07.02.2017. 18:33 ] @
> Savkić, na žalost ne. Može ukratko? (:

Pogledaj onaj link sto sam slao, imas tu sve to detaljno objasnjeno.
[ Rapaic Rajko @ 09.02.2017. 08:16 ] @
Citat:
file za log kod svakog upisa u njega otvaram i zatvaram unutar svakog thread-a isto tako u Synchronize.


Nece biti da je problem do pristupa log file-u.

Pitanje: sta je uopste (odakle) klasa TTask? Gledam, ni u jednom Delphi-ju je nema?

Pozz

P.S. Auh, sad sam pogledao kod gore, tu je svasta pomesano. Za pocetak: sta radi metoda Start?
[ kimisa @ 09.02.2017. 11:31 ] @
TTask mu je vjerovatno neki njegov thread koji se pokreće sa metodom “start“, a dok ne okači njehgovu strukturu, teško je bilo šta prognozirati.
[ savkic @ 09.02.2017. 12:45 ] @
> Pitanje: sta je uopste (odakle) klasa TTask? Gledam, ni u jednom Delphi-ju je nema?

Postoji od kad su ubacene anonimne funkcije, sto je jedno 5 godina. U osnovi je to thread s tim sto kod pises direktno na mestu preko anonimne procedure, Start ti je isto sto i izvrsavanje Execute.
Pogledaj http://docwiki.embarcadero.com...e_Parallel_Programming_Library

[ Milan Milosevic @ 10.02.2017. 12:49 ] @
Pre par godina kad je delphi ukljucio opciju za parallelno programiranje radio sam jedan projekat koji je ukljucivao parallel for petlje i tasking.
Posle velikih peripetija sam odustao i presao na alternativna resenja koje sam malo modifikovao i rade za mene odlicno.
Moja ti je preporuka da batalis delphiju Threading unit i probas sa OmniThreadLibrary koji je u najnovijim verzijam ukljucen u delphi.
[ Rapaic Rajko @ 10.02.2017. 14:48 ] @
Ajmo ovako.

1) TTask ocigledno ima svoj thread koji izvrsava neku proceduru.
2) Ta procedura se moze proslediti kroj kvazi constructor koji je gore upotrebio FranjoZG (class function Create(const Proc: TProc): ITask; overload; static; inline; )
3) Sta je TThreadAdresar? Je li izveden od TThread? Ako DA, onda imamo ovu situaciju. TTask.Start pokrene TTask thread koji zatim izvrsi kreiranje (u prosledjenoj anonimnoj proceduri) TThreadAdresar (novog thread-a?).
4) Posto je izvrsio proceduru, TTask (TTask.Thread) smesta izadje iz job-a, i sto se njega tice on je finished; dalja komunikacija s njim je besmislena (iz aplikacije/glavnog thread-a).
5) E sad, TThreadAdresar (thread li je?) bi trebalo da odradi posao, bez mogucnosti da ikoga obavesti kad je zavrsio, osim sto osvezava kontrole (kroz Synchronize).

Sad KVAKA. Ovo pod 5) nece da radi, jer je u prosledjenog anonimnoj proceduri pozvan a1.Execute(!). To ne ide tako, metoda TThread.Execute se NIKAD ne poziva explicitno iz koda. Kreirani thread ce sam izvrsiti metodu Execute, onog trenutka kad izadje iz nje zavrsio je. U gornjem primeru, TTask.Thread je kreirao TThreadAdresar (sto moze da prodje) a onda i izvrsio njegovu metodu Execute. Tu sad vec nastaju nepredvidivi momenti.
Neko resenje bi bilo da se klasa TThreadAdresar oslobodi (ne bude naslednik) TThread klase, znaci da deklaracija nije vise TThreadAdresar = class(TThread). Ali onda dodati metodu Execute u klasu; ako se ne varam, u postojecem kodu ona je override-ovana (nasledjena od TThread klase).

Pozz
[ FranjoZG @ 11.02.2017. 16:11 ] @
tMyThreadAdresar je "obična" klasa, nije izvedena od TThread. U njoj je skupljeno sve što mi treba za exort/import.

Code:

   tOsThread=class
   ...
   end;

   tMyThreadAdresar=Class(tOSThread)
   ...
   end;


u tOsThread su mi parametri i metode potrebne svim grupama exporta.
osim tMyThreadAdresar postoji još 4 različite klase za različite poslove koji se ne mogu ugurati zajedno.
od klas tMyThreadAdresar kreiran 3 objekta koji su svaki za svoju tablicu.

u a1.Execute se nalazi kod koji obavlja posao. U njemu pristupe main thread-u radim preko Synchronize.
Van threada pristupam - upis: log file-u, tListView kontroli,
param = clasa iz koje samo čitam podatke
preogressbar koji kreiran u thread-u, ali ga prikazujem na main formi.

[ tkaranovic @ 11.02.2017. 18:21 ] @
Evo kako bi moglo da radi:


Code (delphi):



procedure TForm1.Button2Click(Sender: TObject);
begin
  aTask1 := TTask.Create (procedure ()
   begin
     while aTask1.Status <> TTaskStatus.Canceled do
     begin
       sleep(3000);
       ShowMessage ('Hello 1 thread = ' + IntToStr(GetCurrentThreadID));
       TThread.Synchronize(nil,
         procedure
         begin
           ShowMessage ('Hello 1 thread main = ' + IntToStr(GetCurrentThreadID));
         end);
     end;
   end);

  aTask2 := TTask.Create (procedure ()
   begin
     while aTask2.Status <> TTaskStatus.Canceled do
     begin
       sleep(3000);
       ShowMessage ('Hello 2 thread = ' + IntToStr(GetCurrentThreadID));
       TThread.Synchronize(nil,
         procedure
         begin
           ShowMessage ('Hello 2 thread main = ' + IntToStr(GetCurrentThreadID));
         end);
     end;
   end);
  aTask1.Start;
  aTask2.Start;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  if aTask1.Status <> TTaskStatus.Completed then
    aTask1.Cancel;
  if aTask2.Status <> TTaskStatus.Completed then
    aTask2.Cancel;
end;

 

[ savkic @ 11.02.2017. 21:52 ] @
> preogressbar koji kreiran u thread-u, ali ga prikazujem na main formi.

Kako kreiran u thredu? Ni jedna VCL kontrola se ne sme praviti u threadu niti im se sme pristupati.
Elem ako jos nisi resio problem i ako mozes izolovati problem u kod koji ne radi sa bazom, posalji ovde pa ce neko pogledati.
[ captPicard @ 11.02.2017. 22:32 ] @
Meni je ova tema jako zanimljiva pa sam išao proučavati da li postoji neko gotovo rješenje za sinhronizaciju desktop<->online, naletio sam na ovo (ima još toga ali ovo mi izgleda nekako najkvalitetnije):

CopyCat

Jel netko ima iskustva?

Koristio bi za dvije stvari:


1. backup na web mysql (znači one way)
2. replication local -> web <- local (znači da se može raditi sa dvije različite desktop aplikacije a sinhronizacija se odvija preko neta)
[ FranjoZG @ 12.02.2017. 09:52 ] @
kod koji je stavio tkaranovic je ok, ali je jednostavan. pri salnju na web se rade i oderđene kontrole tako da ako sve stavim u jedan unit izgleda poprilično loše.

u D2007 imam sličan kod, tamo koristim class koja je izvedena od tThraed klase i radi OK, u XE7 sam htio "modernizirat" kod i uguran nove stavri (tTask) pa je ispalo s..e (forum neda upisati bezobraznu riječ). I tamo kreiramo kontolu progressbar pa joj dodjelim: progressbar.parent := mainform. Do sada mi nije stvarala probleme.
Kako sam čitao po net-u, jedini uvjet je da se pri izmjeni podataka objekta koji nije u vlasništvu thread-a mora koristiti sinhronyze, a u tTasku postoji i que.
Sve radi ok već 2-3 godine.

Kad nađem kako postaviti slike na formum, postavit ću printscr programa u radu sa 6 progressbara.

Gotov program za sinhronizaciju ne vjerujem da će raditi, možda samo za bckup podataka. Evo primjer: za stranku povreravam plaćenja računa, pa ako ima neplaćene kojima je istekao DVO, setiram indikator za tu stranku tako da nema pristup svojim podacima na web-u.

Postavit ću cijeli kod novog programa ovdje, samo mi treba malo vremena (kojeg trenutno nemam). Moram ga malo pročistiti jer sam u njega ugurao korisnička imena i šifre za pristupe bazama lokalno i na webu.

Bem ti programerski posao :( neki dan mi se raspali win, pa istalacija svega, pa još uvijek otkrivam da nisam dodao sve kontrole u delphi-e, pa projekt koji je trebao biti gotov u petak, a nije još, a ostale stranke za to zabole ona stvar - one hoće svoje...
Zadnja 3 dana radim u smjenama od 18 sati. Gore nego u rudniku!
[ captPicard @ 12.02.2017. 10:19 ] @
Ja taman neki dan odlučio da ču instalirati delphi i sve komponente na još jedan laptop, tako da budem spreman u slučaju havarije :D
[ tkaranovic @ 12.02.2017. 12:58 ] @
Stavio sam kako bi ttask mogao da radi kao thread execute. Da stvari budu jasnije.
Meni taj ttask izgleda kao neki pascal# (pascal sharp) ili delphi#, sto je verovatno i bila namera kad su to pravili.
Inace na stranici o ttasku kaze "Parallel Programming".
Sto bi bilo paralelno programiranje, a to bi bilo da se jednostavno u odvojenim thredovima nesto jednostavno uradi.

Ako treba iz razlicitih threadova pristupati istoj bazi onda to i nije paralelno nego pre unakrsno programiranje.
Odnosno nije jednotsavno i nije nesto sto moze da se uradi sa ttask.
Iz thread mora (ali ne preterano...) da se radi sinhronizacija, ali to (sinhronizacija) nije dovoljno za rad sa bazama.
Cim jedan thread stane u sinhronizaciji, u main kodu, drugi uskace za njim u main thread.
Tako ne moze da se pristupa bazi.
Dok jedan thread ne zavrsi sa bazom drugi ne moze da radi sa njom.
To onda vise ne moze da se zove sinhronizacija. To bi bilo preplitanje ili tako neki izraz.

Ovo sam napisao iz sopstvenog iskustva.
Ako neko ima drugacije informacije zanimalo bi me da procitam neku recenicu o tome.
Ali ne naravno primeri gotovih komponenti za rad sa bazama, nego kako to treba da radi.

[ savkic @ 12.02.2017. 16:36 ] @
@FranjoZG Nisam opet ovo shvatio za progressbar gde ga kreiras, ako je u threadu to ne valja. Ako ti do sada nije pucalo, samo si imao srece.
Sam windows po sebi dozvoljava da se kontrole prave i u threadovim ali tada je taj thread vlasnik tog handla i u tom slucaju je sigurno da se ta kontrola koristi u tom thredu, ako se koristi iz vise threadova moze ali i ne mora doci do problema, to zavisi od nacina upotrebe. VCL je koncipiran tako da se ceo GUI nalazi u MainThreadu zato se za VCL kaze da nije threadsafe. Pristup sa synchronize je siguran ali je prilicno spor i neefikasan, ja u tu svrhu koristim poruke, npr. imam neki worker thread koji nesto radi i onda rezultate (ili progress) treba da prikaze korisniku, sve kontrole su uvek napravljene u glavnom threadu a pomocni thread samo salje poruke (sa PostMessage) koje onda glavni thread prihvata i prikazuje rezultate.

@tkaranovic
Primer koji si dao je delimicno threadsafe, naime jedan ShowMessage (koji je interno VCL forma) se nalazi van Synchronize i zato nije threadsafe, drugi ShowMessage je siguran jer je u okviru Synchronize. Sam primer po sebi ce skoro sigurno raditi bez problema jer je jednostavan pa ni prvi ShowMessage nece praviti probleme ali strogo gledano to nije dobar nacin programiranja. Ako je potrebno prikazati nesto korisniku onda treba koristiti WinAPI MessageBox funkciju koja je threadsafe.

Vecina baza dozvoljava multithread pristup, tako da je sasvim normalno i dozvoljeno da vise threadova istovremeno pristupa bazi, cita i pise podatke. Neke baze imaju i multithread podrsku za kverije sto znaci da komplikovne kverije one mogu podeliti na manje segmente od kojih ce se svaki izvrzavati na jednom coru procesora sto opet znaci da ce rezultati biti brzi. Ako nema podrsku onda to znaci da jedan kveri se izvrzava na jednom procesoru pa ce stoga biti i sporiji. Prednosti deljenja kverija su posebno evidentni na serverskim masinama sa velikim brojem jezgara. Firebird to nema pa je stoga sporiji od vecih baza za neke komplikovane stvari. Sto se tice Delphija, bazama se pristupa preko komponenti, neke komponente su threadsafe i tad mozes da radis sta hoces i odakle hoces. Vecina je threadsafe uz uslov da se svi resursi naprave i koriste u jednom threadu, dakle ako uspostavis posebnu konekciju ka bazi, transakciju, kveri u jednom thredu i sa njima radis samo iz tog threada si potpuno siguran. Da li radis to u threadu ili TTasku je pitanje afiniteta ali su oba slucaja sasvim OK i tu nema zastoja ili cekanja sto se tice same baze (ne racunam na cekanje baze za shared resurse tipa disk, memorija), ako se previse koristi Synchronize posebno ako u petlji kojom se obradjuju slogovi onda ce to naravno biti usko grlo, ali ako se to uradi lepo, prvo sve obradi pa salju podaci glavnom threadu onda tu nema nikakvih problema.
[ tkaranovic @ 12.02.2017. 17:20 ] @
> Primer koji si dao je delimicno threadsafe, naime jedan ShowMessage (koji je interno VCL forma)
> se nalazi van Synchronize i zato nije threadsafe, drugi ShowMessage je siguran jer je u okviru Synchronize.
> Sam primer po sebi ce skoro sigurno raditi bez problema jer je jednostavan pa ni prvi ShowMessage nece
> praviti probleme ali strogo gledano to nije dobar nacin programiranja. Ako je potrebno prikazati nesto
> korisniku onda treba koristiti WinAPI MessageBox funkciju koja je threadsafe.

To je primer sa linka koji si ti dao. Ja sam samo prosirio primer.

Taj primer radi u XE7, a ako pogledas kako tamo radi showmessage videces da je threadsafe.



> Vecina je threadsafe uz uslov da se svi resursi
> naprave i koriste u jednom threadu, dakle ako uspostavis posebnu konekciju ka bazi, transakciju, kveri u
> jednom thredu i sa njima radis samo iz tog threada si potpuno siguran.

Sa ovom recenicom se potpuno slazem :)
[ savkic @ 12.02.2017. 19:39 ] @
> To je primer sa linka koji si ti dao. Ja sam samo prosirio primer.
> Taj primer radi u XE7, a ako pogledas kako tamo radi showmessage videces da je threadsafe.

ShowMessage threadsafe? Ako je Vista ili vise i ako je setovan UseLatestCommonDialogs onda ce se koristiti TaskDialogIndirect API funkcija. Za nju ne znam da li je threadsafe, pretpostavicu da vazi standardno da se mora koristiti iz threada u kome je napravljena. Kako ima ima i neke callbackove koji ce verovatno zavrsiti u glavnom threadu a i sama funkcija koristi Application (koji nije threadsafe), bez detaljnog istrazivanja ne mogu biti skroz siguran ali ja ne bih nju koristio. Svakako ako negde u Delphi helpu daju primer sa ShowMessage u threadu van Synchronize to je greska zato sto sigurno ne radi na WinXP ili kad se resetuje UseLatestCommonDialogs.
[ tkaranovic @ 12.02.2017. 19:39 ] @

> Taj primer radi u XE7, a ako pogledas kako tamo radi showmessage videces da je threadsafe.

Ovo naravno nije tacno... da neko ne pomisli da jeste ;)
[ tkaranovic @ 12.02.2017. 19:40 ] @


Sad vidim da smo istovremeno poslali poruku :)
[ FranjoZG @ 12.02.2017. 23:20 ] @
Moj stari D2007 program:
- Progress bar kreiram u threadu i koristim ga samo u tom threadu jedino što se prikazuje na main formi.
- svaki thread (njih 6) kreira svoju konekciju na bazu kao qry za pristup bazi, onoj lokalnoj (FB) i onoj na web-u (MySQl). nisam imao problems s tim, radi nekoliko godina ispravno uz ponekad grešku pristupa web bazi pa sam ugradio provjere, te kad ne prođe, tj. javi milo koju grešku ponavljam taj prijenos (ponovno kreiram thread) i tako 5 puta, pa ako u 5 puta nije odradio posao, upišem u log i odustanem. Ka se svi thread-ovi završe, zatvarm program.

Savkić, kako si napisao u trečem odlmku, tako radim s bazom. Čitam da FB 3 će moči koristiti više procesora, treba probati. Budući da ne mogu sa FB3 klijenotm pristupiti na FB 1.5, ostaje za neka druga vremena...

Sa klasom tThread u D2007 mi to sve skupa radi. U XE7 sam pročitao za parallel programing, pa reko da probam. Izgleda da to stvarno nije za kompliciranije stvari. Probat ću još izbaciti korištenje objekata u tTask-u te sve prepisati u preocedure pa onda njih pozivati iz tTask-a.
[ tkaranovic @ 13.02.2017. 06:46 ] @
Onda svaki thread im svoju konekciju na FB server.
Ako je tako onda je to isto kao da se razliciti programi povezuju na FB server.

Pretpostavljam da se iz lokalne FB (preko servera) samo citaju a ne i upisuju.
Jer ako bi se upisivali sa jednim threadom (jednom ili prvom konecijom),
onda ne bi mogli da se procitaju upisani podaci sa drugim threadom (odnosno drugom konekcijom).
[ FranjoZG @ 13.02.2017. 08:51 ] @
U lokalu bazi se iz thrad-a i upisuju podaci, setiraju se statusi prijenos: datum, status koji se koriste pri sljedećem pokretanju kako se ne bi prenosila cijela tablica već samo mijenjani podaci.
Sam rad s bazom FB 1.5 nije ništa brži s thread-ovima on onoga bez njih, ali se dobije na ukupnom poslu koji program odradi jer se vrti paralelno i ne čeka jedan na drugi (provjereno):
- čitanje iz lokalne baze
- obrada. Dio je čisti prijenos podataka na web, a dio je obrada koja kombirnira više tablica te računa koješta.
- slanje na web

Starim programom sam zadovoljan kako radi mada bih ga napisao ponovo jer je vremenom više puta proširivan i prerađivan pa mi kod ne izgleda lijepo (ko da ga netko vidi :) ), neke stvari bih drugačije napravio, a tTask mi je izgledao primamljivo. Kako stvari stoje, ostat ću pri klasi Thread, ali u XE7.

Kad bi si netko dao truda pa napisao kuharicu za krištenje Thread-ova i Task-a... ali ne ono što se može pronaći po net-u jer su u principu jednostavni primjer ("Hello word"), a to baš i nije od pomoći kad upadneš u probleme.
[ tkaranovic @ 13.02.2017. 09:45 ] @
U vezi threadova nisam imao primedbu, nego me samo interesoavalo kako rade.
Tako kako rade (koliko sam razumeo korake), startuju se i procidaju podatke, razmene sa webom i upisu, a onda prestanu sa radom je OK.
Tako i treba da rade zajedno, mene ja samo zanimao kako tacno.

Sto se kuvara tice i ja bi ga rado citao :)
Inace moj vikend je prosao...
[ savkic @ 13.02.2017. 21:05 ] @
> Progress bar kreiram u threadu i koristim ga samo u tom threadu jedino što se prikazuje na main formi.

To je greska, nista sto se tice GUI kontrola ne sme u thread, kreiranje nije izuzetak. U jednostavnim slucajevima to ce biti OK ali pre ili kasnije u nekom programu ces poceti da dobijas random AV.

> Savkić, kako si napisao u trečem odlmku, tako radim s bazom. Čitam da FB 3 će moči koristiti više procesora,
> treba probati. Budući da ne mogu sa FB3 klijenotm pristupiti na FB 1.5, ostaje za neka druga vremena...

Uradili su podrsku za SMP, to u principu znaci da delovi koji se izvrsavaju na vise procesora mogu da koriste isti kes, bice boljitak u super server arhitekturi, za classic mislim da ne.

> Sa klasom tThread u D2007 mi to sve skupa radi. U XE7 sam pročitao za parallel programing, pa reko da probam.
> Izgleda da to stvarno nije za kompliciranije stvari. Probat ću još izbaciti korištenje objekata u tTask-u te sve prepisati
> u preocedure pa onda njih pozivati iz tTask-a.

TTask nije sigurno problem, ako dobijas AV to znaci da imas neki race condition izmedju threadova, da li je to zbog VCL kontrola, pristupa bazi ili nesto trece je tesko reci.

> Pretpostavljam da se iz lokalne FB (preko servera) samo citaju a ne i upisuju.
> Jer ako bi se upisivali sa jednim threadom (jednom ili prvom konecijom),
> onda ne bi mogli da se procitaju upisani podaci sa drugim threadom (odnosno drugom konekcijom).

FB/IB imaju jednu odlicnu osobinu zbog svoje MGA arhitekture da mozes napraviti transakciju (kveri) koja vidi sve promene cim se komituju a ne zauima nikakve resurse (ne utice na probleme zbog zaostalih OIT/OAT). Ja obicno otvorim jednu takvu readonly transakciju na pocetku i drzim je uvek otvorenu i sva citanje (kad je to moguce) radim preko nje, mnogo zavisi od komponenti koji se koriste i da li one dozvoljavaju setovanje parametara transakcije. Uglavnom takva transkacija treba da ima sledece flegove:
read
read_committed
nowait
rec_version


[ tkaranovic @ 14.02.2017. 10:31 ] @

> FB/IB imaju jednu odlicnu osobinu zbog svoje MGA arhitekture da mozes napraviti transakciju (kveri)
> koja vidi sve promene cim se komituju a ne zauima nikakve resurse (ne utice na probleme zbog
> zaostalih OIT/OAT). Ja obicno otvorim jednu takvu readonly transakciju na pocetku i drzim je uvek
> otvorenu i sva citanje (kad je to moguce) radim preko nje, mnogo zavisi od komponenti koji se
> koriste i da li one dozvoljavaju setovanje parametara transakcije. Uglavnom takva transkacija treba da ima sledece flegove:
> read
> read_committed
> nowait
> rec_version

Znam ja da ti to tako radis ;) (posto si napisao "Ja obicno otovorim..." :))
Ali to je jedna od transakcije u okviru iste konekcije.

Ovde je bila rec o vise threadova koji imaju svoje koneckije.
Odnosno, to sam ja tako zakljucio a Franjo nije demantovao.

Ako hoces da kazes da sve treba da ide preko jedne konekcije onda tako napisi.

U svakom slucaju tako kako rade vise konecija mogu da rade i rade.
Jedino je potrebno da u isto vreme ciatju ono sto je upisano u prethodnom radu.

Naravno, ja open nastavljam onako kako sam sam zakljucio da radi sa vise konekcija, a Frano nije npisao da ne radi tako.
[ FranjoZG @ 14.02.2017. 15:23 ] @
Svaki thread mi je kao zaseban program, sa svim što mu treba i radi neovisno o ostatku programa. Izuzetak je već opisani progressbar i klasa za parametre.

Imam definiranu klasu: tMyParam u kojoj su potebni parametri za rad: ime baze, user name, pass itd.
Svi parametri su definirani kao
class property
tako da ih jednom u programu postavim i vidim ih u svakom thredu. Ne mijenjam ih thread-u, samo čitam, ne kreiram objekt od te klase.

Kod starta programa upisujem parametre u klasu parametara i postavljam varijable (public u main-u):
Thread1Started := true
Thread2Started: = true
...

iz svakog threada, kao zadnju nardebu, pozivam proceduru u main formi s parametrom ImeThread-a
procedura indikator thread (prema parametru) postavi na false i provjerava da li su svi indikatori na false, ako jesu - gasim program (program se starta automatski svakodnevno u x sati).

Volio bih da se vratite na:

1. Razlika između tParallel i tThread
2. kreiranje objekta u tParallel i izvršavanje

Jel tko obečao napraviti upute za paralelno programiranje, korištenje thread-ova itd ? :)
Ovdje sam negdje skinuo uputstvo za kreiranje user kontrola (na želost ne sjećam se tko ga je napisao), pomoglo mi je više nego sav ostali net.
[ savkic @ 14.02.2017. 17:33 ] @
> 1. Razlika između tParallel i tThread

Mislis na TTask i TThread?

TTask je wrapper oko TThreada, utility klasa koja ti omogucava da neki kod izvrsis u threadu a da ne moras posebno izvoditi klasu, dakle u osnovi TTask skracuje vreme pisanja naspram direktno koriscenja TThreada. Sva pravila o threadsafe programiranju koja vaze za threadove vaze i za taskove.

> 2. kreiranje objekta u tParallel i izvršavanje

1) Nikad ne kreiraj VCL kontrole
2) Kreiraj sta god hoces ostalo uz opasku da moras voditi dodatno racuna ako ce se to sto si kreirao koristiti i u drugim threadovima, najbolje je da to sto si kreirao u thredu, iskljucivo i koristis u njemu.
3) TTask se izvrsava (postoji) dokle kod koji si napisao se ne zavrsi ili dok ga ti ne otkazes. Anonimna procedura (ili procedura) koju si naveo prilikom kreiranja TTaska je zapravo kod koji ce ici u Execute napravljenog threada.

> Jel tko obečao napraviti upute za paralelno programiranje, korištenje thread-ova itd ? :)

Bilo je tokom godina ovde govora o tome tu i tamo, mozda neki search pomogne, i naravno na netu se moze naci dosta toga na tu temu.
[ FranjoZG @ 14.02.2017. 22:08 ] @
Pitanje:
ako imaš više thread-ova koji upisuju u isti log file, obični text file. Gdje ga "uvaliti"? U main thread pa pozivati proceduru iz drugog threada ili u svakom threadu kreirati proceduru za upisu file?

Ako je proc. za upis u log file u main tread-u, tada mogu voditi računa da pričekam sa novim upisom dok stari nije završen.
Ako je u thread-u koji treba i upisati podatke, ne zna da li možda neki treči thrad pokušava upisati, neće li se tada možda "sudariti"?

Npr ovako za poziv procedure iz main thread-a:
Code:

type
  tProc= procedure(Tekst: string) of object;

  tMailThread = class(TThread)
  private
    { Private declarations }
    fLogProc: tProc;
  protected
    procedure Execute; override;
  public  
    property LogProc: tProc read fLogProc write fLogProc;
  end;


u main threadu kažem novom thread-u koja mu je to procedure:

Code:

...
      SendMailThread := tMailThread.Create(true);
      SendMailThread.Log := WriteLog;
      SendMailThread.Resume;
...

procedure MainFrm.WriteLog(Tekst: string);
begin
...
end;
[ savkic @ 15.02.2017. 00:58 ] @
> ako imaš više thread-ova koji upisuju u isti log file, obični text file. Gdje ga "uvaliti"? U main thread pa
> pozivati proceduru iz drugog threada ili u svakom threadu kreirati proceduru za upisu file?
> Ako je proc. za upis u log file u main tread-u, tada mogu voditi računa da pričekam sa novim upisom dok stari nije završen.
> Ako je u thread-u koji treba i upisati podatke, ne zna da li možda neki treči thrad pokušava upisati, neće li se tada možda "sudariti"?

Kako doista upisujes stvari u fajl, da li TFileStream ili WinApi funkcije CreateFile/WriteFile?
TFileStream nism siguran da je threadsafe, ne bih se kladio, WriteFile jeste ako koristis asinhrono pisanje ali moze doci do mesanja sadrzaja ako ides sa sinhronim pristupom.
Sve u svemu, najsigurnije je da ti obezbedis threadsafe pisanje u log. Recimo napravis jednu globalnu funkciju
AddToLog(const AText: string) i dalje nju pozivas iz svih treadova. Najjednostavniji nacin da je zastitis je sa TCriticalSection.
[ Rapaic Rajko @ 16.02.2017. 08:34 ] @
Log file: zar ne rece negde ranije da upis u log radis iz main thread-a, tako sto iz worker thread-a pozoves Synchronize(MetodaZaUpisULog)?

S ovim si resio problem, nema sudaranja/kolizije oko Log fajla. Synchronize() je nekad radilo preko poruka (SendMessage(), funkcija koja ceka obradu poruke). Losa strana je sto worker thread stoji dok MainThread ne odradi posao/poruku. Takodje, ukoliko MainThread iz nekog razloga stane (intenzivna obrada, dead loop ili slicno), svi worker thread-ovi ce stati na pozivu Synchronize().

Drugi nacin (moj omiljeni) je upravo predlozio Igor (savkic), a to je pisanje posebne threadsafe klase za upis u log file. Za ovo pogledaj klasu TThreadList u unit-u Classes (Delphi 7 ili raniji); nit manje klase nit mocnijeg koda ;); efektan primer kako se pravi threadsafe resurs.

Pozz
[ salvaric @ 16.02.2017. 10:56 ] @
Što se tiče upisa u log fajl, i po meni je najbolja varijanta da napraviš zaseban thread za to.

U prilogu je jednostavan primer, koji kod mene radi bez ikakvih problerma i peripetija.
[ salvaric @ 17.02.2017. 12:51 ] @
Citat:
Log file: zar ne rece negde ranije da upis u log radis iz main thread-a, tako sto iz worker thread-a pozoves Synchronize(MetodaZaUpisULog)?

S ovim si resio problem, nema sudaranja/kolizije oko Log fajla. Synchronize() je nekad radilo preko poruka (SendMessage(), funkcija koja ceka obradu poruke). Losa strana je sto worker thread stoji dok MainThread ne odradi posao/poruku.


Ne bih se složio sa ovim rešenjem Synchronize() metode iz main thread-a za upis u log ili bilo koje druge metode, ne stoji samo worker thread dok se metoda ne izvrši, već stoji i main thread zamrznut, i čemu je onda poenta poziva iz thread-a, ako će korisnik čekati da worker odradi posao.
[ tkaranovic @ 17.02.2017. 13:29 ] @

Salvaricu, tvoj log fajl ima 60 linija a pravis 100 threada. Nedostaje 40 linija?

Ti namerno pravis sum ili ne pratis radnju u ovoj temi?

Slicno tom tvom primeru bi bilo sa Synchronize().

Ono sto je Savkic napisao (TThreadList je isto to) to moze da predupredi.

[ salvaric @ 17.02.2017. 14:04 ] @
Napustio si program pre nego što su svi thread-ovi bili izvršeni, nije zaštićeno sa te strane, tako da bi ispisao svih 100 da je main thread ostao malo duže živ.
Citat:
Slicno tom tvom primeru bi bilo sa Synchronize().

Bi, bilo u koliko se metoda nalazi u worker therad-u, a u koliko je u main thread-u, glavna forma bi bila zamrznuta dok se ne izvrši. Možda u ovom primeru kod upisa u log fajl išlo bi brzo, i nebi se ni primetilo, al neke malo zahtevnije metode bi zahtevale malo više vremena.
[ savkic @ 17.02.2017. 14:19 ] @
Zapravo ja sam rekao da moze obicna AddtoLog funkcija koja se stiti sa CriticalSectionom, nema potrebe za TThreadList overheadom, ne bi nista ubrzao u odnosu na obican CS.
[ tkaranovic @ 17.02.2017. 17:43 ] @
> Bi, bilo u koliko se metoda nalazi u worker therad-u, a u koliko je u main thread-u, glavna forma bi bila zamrznuta dok se ne izvrši. Možda u ovom primeru kod upisa u log fajl išlo bi brzo, i nebi se ni primetilo, al neke malo zahtevnije metode bi zahtevale malo više vremena.

Ovo je (formalno) tacno. Izgubio sam iz vida da koristis main thread.


> Napustio si program pre nego što su svi thread-ovi bili izvršeni, nije zaštićeno sa te strane, tako da bi ispisao svih 100 da je main thread ostao malo duže živ.

Niam ja startovao program nego u arhivi koju si poslao log fajl ima 60 linija.

Ovde mozes da cekas koliko hoces nece nikad biti 100 linija.