TBitmap a vlákna... – Delphi – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

TBitmap a vlákna... – Delphi – Fórum – Programujte.comTBitmap a vlákna... – Delphi – Fórum – Programujte.com

 

Sniper
~ Anonymní uživatel
215 příspěvků
10. 4. 2011   #1
-
0
-

Zdravím,
potřeboval bych poradit s jednou (pro mě) zapeklitou věcí. Jde o následující:
Mám program který dávkově zpracovává obrázky (soubory). Když pominu hlavní vlákno, tak v programu běží řídící vlákno (stará se o seznam souborů ke zpracování, vytváří pracovní vlákna a rozděluje mezi ně práci) a jedno nebo víc pracovních vláken. Nejsem takový frajer abych každý jednotlivý obrázek zpracovával ve více vláknech, takže to vypadá tak, že jedno pracovní vlákno dostane ke zpracování jeden soubor a nějaké další informace, a dál už si jede na vlastním písečku. Po dokončení a uložení výsledku si řekne řídícímu vláknu o další, to mu ho buď přidělí, nebo pokud už jsou všechny zpracovány mu řekne aby se ukončilo.
Toliko k objasnění situace. A teď k problému.
Pracovní vlákno má deklarovanou bitmapu (TBitmap) v sekci private (více viz ukázka kódu dále). Do této bitmapy se načte zpracovávaný soubor, provedou se potřebné úpravy (včetně např. změny velikosti nebo barevné hloubky), a výsledek se uloží. Bitmapa existuje celou dobu co vlákno, čili se pro každý zpracovávaný soubor NEvytváří nová (mám pro to své důvody). Nepřistupuje k ní žádné jiné vlákno než to které ji vytvořilo.
Jenomže program mi při zpracovávání ve více-méně náhodných situacích hlásí chybu, konkrétně nedostatek paměti (EOutOf Resources nebo tak nějak, číslo chyby je 8). MemoryLeak tam ale nikde není (koneckonců program si bere tak maximálně 15MiB RAM, záleží na počtu pracovních vláken). A mě by zajímalo proč tomu tak je. Google moc neporadil, všude se řeší jenom přístup do jedné bitmapy z více vláken - to není tento případ.

ukázka kódu (podstatné věci kolem bitmapy):

TWorkThread = Class(TTHread)

private
thrWorkBitmap: TBitmap;
...
constructor TWorkThread.Create(...
begin
...
thrWorkBitmap := TBitmap.Create;
...
end;

destructor TWorkThread.Destroy;
begin
thrWorkBitmap.Free;
...
end;

procedure TWorkThread.Execute;
begin
//zde pracuji s bitmapou
end;


Prozatím jsem udělal to, že bitmapě zamykám canvas a vytvářím a uvolňuji ji uvnitř procedury Execute, zdá se že to pomáhá. Ale stejně mě nejde do hlavy, proč když k ní přistupuje jenom jediné vlákno, to dělá takovouhle paseku. Budu rád za jakoukoliv radu nebo objasnění.
Snad vás délka mého příspěvku neodradila a dočetli jste až sem :).
Jenom doplním že se považuji za začátečníka (tak mě hned nekamenujte), dělám to na WinXP (32bit) a Delphi 7 Personal.

Nahlásit jako SPAM
IP: 90.179.201.–
nervak0
Věrný člen
10. 4. 2011   #2
-
0
-

Tipovací soutež? :) Jak s tou bitmapou pracuješ, a která operace tu chybu vyhodí?

Našel jsem něco s vynucením DIB místo DDB (HandleType, PixelFormat), ale nemám ponětí, jestli to řeší Tvůj problém.

Nahlásit jako SPAM
IP: 213.211.51.–
Sniper
~ Anonymní uživatel
215 příspěvků
10. 4. 2011   #3
-
0
-

Běží to ve více vláknech a delphi mi neřekne víc než vlákno kde ke chybě došlo. Takže pokud mi poradíte jak v několika běžících vláknech zjistit kde přesně nastala chyba tak budu taky rád. Ale v podstatě tam proběhne jenom následující (mírně zjednodušeno):
- načtení souboru thrWorkBitmap.LoadFromFile(FileName)
- zpracování obrázku pomocí metod thrWorkBitmap.Canvas.CopyRect a Draw (samotné "efekty" se provádějí mimo tuto bitmapu)
- změna velikost bitmapy způsobem thrWorkBitmap.Width := iX, thrWorkBitmap.Height := iY
- někdy ještě změním barevnou hloubku thrWorkBitmap.PixelFormat := pf24bit (nebo jiný, podle nastavení)
- uložení do výstupního souboru thrWorkBitmap.SaveToFile(OutputFileName)
Co jsem se tak pokoušel to krokovat tak chyba vzniká tam kde měním velikost nebo barevnou hloubku (tj. i při nahrávání ze souboru). DIB/DDB jsem vůbec neřešil, ani nevím proč bych měl (ale jsem začátečník, takže třeba právě tam je chyba, nevím). To co provádím s obrázky nejsou žádné šílenosti, jenom pár základních efektů, a jak jsem říkal ani jedno nedělám přímo v thrWorkBitmap, ale ve vedlejších bitmapách a jenom nakonec na správné místo zkopíruji výsledek. Že k chybám nedochází někde mimo zpracování této hlavní bitmapy vím jistě.
Mě skutečně nejde o nějaké efekty a zpracování bitmapy jako takové, ale o provádění zmíněného ve vláknech. Prostě bych rád věděl na co se mám při zpracování bitmapy ve vlákně zaměřit aby to bylo ok.

Nahlásit jako SPAM
IP: 90.179.201.–
nervak0
Věrný člen
10. 4. 2011   #4
-
0
-

Já už Delphi nemám, takže to nemůžu zkusit, ale nejjednodušší bude prostě tam přidat nějaké výpisy.

Ono je funkčně jedno, jestli je to DIB nebo DDB, ale DIB žere jen virtuální pamět, zatímco DDB je z omezenějších zdrojů, takže bych to rozhodně zkusil. Nejlépe asi podobně jako tady http://docwiki.embarcadero.com/CodeExamples/en/LoadFromFile_(Delphi)

Nahlásit jako SPAM
IP: 213.211.51.–
Sniper
~ Anonymní uživatel
215 příspěvků
10. 4. 2011   #5
-
0
-

Dobrá, ale já pořád nechápu proč bych měl řešit jestli je to DIB nebo DDB a jak mi to pomůže? Tu bitmapu nikde nezobrazuji, paměti je dostatek a GDI (a vůbec všech) handlů je pořád stejně i po několika desítkách průchodů. Se samotným zpracováním obrazu problémy nemám.
Vím že při přístupu ke canvasu bitmapy z několika vláken je třeba canvas zamykat, ale není mi jasný proč to musím dělat i tady kdy k bitmapě přistupuje jen jedno vlákno (a není to hlavní vlákno).
Jinak těmi výpisy myslíš něco jako log (nebo zprávy atp...) kde zachytím kde přesně se to "vysralo"? To už tam mám.

Nahlásit jako SPAM
IP: 90.179.201.–
Sniper
~ Anonymní uživatel
215 příspěvků
10. 4. 2011   #6
-
0
-

Abych jenom blbě neplácal, tak sem dám komplet vlákno (osekané o veškeré serepatičky a funkce - CopyRect a Draw jsou nesmyslné, je to tam jenom pro test, ale i v téhle podobě to padá), co je tam špatně?.

type

TWorkThread = Class(TThread)
private
thrThreadIndex: Integer;
thrProcessedFile: String;
thrWorkBitmap: TBitmap;
thrControlThreadWnd: HWND;
thrSettings: settings_r;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean; const Index: Integer);
destructor Destroy; override;
published
property ProcessedFile: String read thrProcessedFile write thrProcessedFile;
property ControlThrWnd: HWND read thrControlThreadWnd write thrControlThreadWnd;
end;

constructor TWorkThread.Create(CreateSuspended: Boolean; const Index: Integer);
begin
inherited Create(CreateSuspended);
FreeOnterminate := True;
Priority := tpLower;
thrThreadIndex := Index;
thrWorkBitmap := TBitmap.Create;
MREW_Settings.BeginRead;
try
thrSettings := Settings;
finally
MREW_Settings.EndRead;
end;
end;

destructor TWorkThread.Destroy;
begin
thrWorkBitmap.Free;
inherited;
end;

procedure TWorkThread.Execute;
begin
While not Terminated do
try
thrWorkBitmap.LoadFromFile(thrProcessedFile);
thrWorkBitmap.PixelFormat := pf24bit;
thrWorkBitmap.Canvas.CopyRect(Rect(0,0,thrWorkBitmap.Width,thrWorkBitmap.Height),thrWorkBitmap.Canvas,Rect(0,0,thrWorkBitmap.Width,thrWorkBitmap.Height));
thrWorkBitmap.Canvas.Draw(0,0,thrWorkBitmap);
thrWorkBitmap.Width := thrWorkBitmap.Width - 100;
SendMessage(thrControlThreadWnd,WM_THRCOMMSG,thrThreadIndex,TRV_DONE);
except
SendMessage(thrControlThreadWnd,WM_THRCOMMSG,thrThreadIndex,TRV_ERR_GEN or (GetLastError shl 16));
end;
end;

MREW_Settings je TMultiReadExclusiveWriteSynchronizer.

Nahlásit jako SPAM
IP: 90.179.201.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 2 hosté

Podobná vlákna

Vlákna — založil blackman.ce

Vlákna — založil delphak

Vlakna — založil Homer

Vlakna — založil insider

Vlákna — založil Tayson

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý