Avatar billede phansen Nybegynder
13. november 2000 - 16:32 Der er 12 kommentarer og
1 løsning

Tråde, synkronisering

Hej!

Jeg er i gang med at lave et program i delphi der bruger multithreading..
I den sammenhæng har jeg et varierende antal tråde, der hver har en event, der hedder OnStatusUpdate som sætter en StatusHandler (TNotifyEvent) til at pege på en procedure. Trådene kalder så hver især deres egen statushandler (altså hvad den peger på) fra tid til anden.
Nu er det så, at jeg har alle mine trådes statushandler til at pege på den samme procedure i hovedprogrammet, som ser nogenlunde sådan her ud:

procedure TForm1.NewStatus(Sender: TObject);
var
  f: textfile;
begin
  assignfile(f, \'c:\\log.txt\');
  reset(f);
  writeln(f, (sender as mythread).status.time, \': \', (sender as mythread).status.info);
  closefile(f);
end;

Som den håbløse selvlærte amatør jeg er, aner jeg selvfølgelig ikke en fløjt om, hvordan tråde i bund og grund fungerer..
Har hver tråd en instruction pointer der peger på det samme sted i noget shared hukommelse? (altså på denne procedure)? Eller hvordan fungerer det?
Problemet er, at der nogen gange kommer nogen ret mærkelige halve linier i log-filen, der så brat afbrydes af en ny indgang.. Programmet skulle gerne kunne køre sig selv i en rum tid ad gangen, og jeg er lidt bange for, at det også går ned pga. at dette er lavet forkert..

Hvordan BURDE man lave det her?
Avatar billede borrisholt Novice
13. november 2000 - 16:37 #1
bruge syncronize()

Jens B
Avatar billede phansen Nybegynder
13. november 2000 - 18:00 #2
Har prøvet, dur ikke.
Synchronize brokker sig gevaldigt:
Incompatible types: \'TThreadMethod\' and \'procedure, untyped pointer or untyped parameter\'...

Jeg prøvede at kalde den således:

type
  blah = class(tthread)
    statushandler: tnotifyevent;
    // etc
  end;


procedure blah.setstatus;

begin
  Synchronize(StatusHandler);
end;
Avatar billede phansen Nybegynder
13. november 2000 - 18:04 #3
ps.. under fem minutter.. damn du er quick!
Avatar billede delphi Nybegynder
14. november 2000 - 08:49 #4
Du har (tilsynladende) brug for noget hjælp vedr. threading.

Hver thread du kører/starter vil have sit eget adresse område, dvs. sine egne variable, instruction pointere mv.  Men hvis dine Threads kalder rutiner, der ikke er en del af den pågældende thread, så er det dit ansvar at sørge for at dette kald er \"Thread-safe\"
(Thread-safe: se følgende link hos borland:)
http://community.borland.com/article/0,1410,25609,00.html

Problemet er som jeg umiddelbart ser det, at din NewStatus metode er global, dvs, den eksistere kun som en enkelt instans i dit hovedprogram (som iøvrigt også er en thread under windows), og benytter en lokal variabel: \"f\".  (Det gør ingen forskel om \"f\" er global - det der er fidusen er, at den kun eksistere EN gang i dit program - ikke en gang pr. thread.) 

Det jeg umiddelbart kan se, der sker i dit program, er at hver gang der sker et thread skift vil du risikere at NewStatus kaldes, hvorved \"f\" overskrives/åbnes på ny, data skrives og filen lukkes.  Når du returnere til den thread, der allerede var igang med at gemme data, er \"f\" ikke længere en valid handle, dvs filen er lukket, og dine data går tabt.  -Har jeg ret?

Løsningen er altså at sørge for at kun en thread kan accesse NewStatus af gangen.  Løsningen må her være at bruge en semaphore til at styre adgangen.

Check iøvrigt følgende links:
  http://community.borland.com/article/0,1410,25707,00.html
  http://community.borland.com/article/0,1410,10452,00.html
  http://delphi.about.com/compute/delphi/cs/kbthread/index.htm?terms=thread
  http://delphi.about.com/compute/delphi/gi/dynamic/offsite.htm?site=http%3A%2F%2Fcommunity.borland.com%2Farticle%2F0%2C1410%2C22411%2C00.html

De sidste to links er fra Delphi.About.Com, der iøvrigt har en masse om threads i Delphi


Delphi.
Avatar billede borrisholt Novice
14. november 2000 - 09:29 #5
phansen> Hvis du sender mig en mail så har jeg lavet nogle eksempler på hvordan man laver det der med trås synkronisering ....

Jens B
Avatar billede delphidaner Nybegynder
14. november 2000 - 11:34 #6
Jeg har et forslag til en work-around løsning:

Hvad med at lade NewStatus-proceduren tilføje teksten til en buffer (f.eks. TStringList), og have en anden thread til at skrive bufferindholdet til filen, når der er noget i bufferen?
Avatar billede delphi Nybegynder
14. november 2000 - 11:45 #7
Det løser intet!  Tråd skiftene kan lige så vel ske i tilskrivningen til en stringlist - eller for den sags skyld mens listen udskrives.

Løsningen er at benytte en beskyttet resource.  Her er der flere metoder: semapohores, atoms etc etc.

Delphi.
Avatar billede delphidaner Nybegynder
14. november 2000 - 11:49 #8
Ups, du har ret! Jeg kan godt se hvad du mener.
Avatar billede borrisholt Novice
14. november 2000 - 11:51 #9
delphi  > Lige bestemt! Det er præcis hvad mine eksempler går ud på ...

Jens B
Avatar billede phansen Nybegynder
14. november 2000 - 11:57 #10
delphi> Joda.. kan jo også ske at den samme thread kalder NewStatus to gange i træk (meget hurtigt), så den første gang ikke når at eksekvere færdigt? måske? Jeg vil gerne frem til hvordan det egentlig fungerer.
Du siger at hver thread har sit eget adresserum og instruction pointer. Dvs. hvis jeg kalder NewStatus (via statushandler) inde i en thread, så bliver denne thread\'s instruction pointer sat til at pege på et sted i det globale adresseområde (hoved-tråden\'s) ?? Eller hvad?

Og hvad sker der, hvis min thread står og laver en masse fjol i Execute el. lign., og jeg kalder en af trådens metoder - bliver execute midlertidigt stoppet, den anden metode kørt og execute så genoptaget? Eller er det bare ude med execute?


delphidaner> jo, udmærket.. men nu har jeg fået blod på tanden og vil vide hvordan det fungerer, til næste gang jeg løber ind i problemet.. (Mon ikke jeg løber panden mod en mur mht. synkronisering af tråde igen.. det tror jeg nok jeg gør!)
Avatar billede phansen Nybegynder
14. november 2000 - 11:59 #11
Ups, kom til at lukke spørgsmålet?.. Det var ikke meningen?.. Du skal nok få et par point oven i hatten hvis du kan svare mig på det sidste --> delphi :o)
Avatar billede delphi Nybegynder
14. november 2000 - 12:14 #12
>Joda.. kan jo også ske at den samme thread kalder NewStatus to gange
>i træk (meget hurtigt), så den første gang ikke når at eksekvere færdigt?

Det vil næppe ske.  Vi snakker jo ikke interrupt styring hvor et interrupt afbryder sig selv.  En thread er bare en rutine (sløjfe) der står og kører - ind i mellem bliver, på vilkårlige tidspunkter, den bare afbrudt af OPsytemet/CPU\'en.  Det er ikke sådan at den starter forfra efter en afbrydelse (som et interrupt) - threaden ved faktisk slet ikke at den har været afbrudt når den genstarter.

>Du siger at hver thread har sit eget adresserum og instruction
>pointer.

Ja - Hver thread har sin egen stak og på denne stak ligger alle de lokale variable mv. du måtte have valgt at oprette i den pågældende tråd.

>Dvs. hvis jeg kalder NewStatus (via statushandler) inde i en thread,
>så bliver denne thread\'s instruction pointer sat til at pege på et
>sted i det globale adresseområde (hoved-tråden\'s) ?? Eller hvad?

Jeps. 

>Og hvad sker der, hvis min thread står og laver en masse fjol i...

Som beskrevet ovenfor.  Der springes ud fra execute, subrutinen køres og der returneres til execute der udfører næste linie i koden.  Dette gælder uanset om der er 0 eller 1000 thread skift i det pågældende tidsrum.


Læs iøvrigt artiklen:

http://community.borland.com/article/print/0,1772,22411,00.html

Det er en artikel på 7 sider kaldet \"Delphi threading by example\".  Forfatteren benytter en meget nemt forståelig metode til beskyttelse af critical sections, netop hvor der arbejdes med en datafil.

Delphi

PS: Brug hellere pointsne på et nyt spændende spørgsmål - jeg har nok.
Avatar billede phansen Nybegynder
14. november 2000 - 12:30 #13
Tusind tak :o)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester