The main thread waits for this thread to end, puts the bitmap on the
display, then frees that, allocates another TBitmap, and creates and starts
the thread again.
People using my program find that after a number of these iterations, the
screen shows only white instead of one of the bitmaps it should be
displaying. I'm unable to reproduce the problem on my machine, which is
slower than theirs.
The previous version of the program doesn't use threads, and doesn't have
the problem, so I'm leaning toward a synchronization problem.
Is there something either the main thread or the other thread can do to make
sure the bitmap is completeley drawn in memory before the thread terminates?
Or is having a thread draw to a bitmap owned by the main thread just a bad
idea?
Thanks,
Elliott
MyBitmap.Dormant;
MyBitmap.FreeImage;
This will force the thread into waiting until the whole riffraff under the
hood is performed. Also, make sure not to reference the Bitmap at the same
time from two threads, or main <-> thread. Use a proper synchronizing scheme
(TCriticalSection or TMultiReadExclusiveWriteSynchronizer).
I had these white squares too, not any more now (see ABC-View Manager)
Elliott Shevin <she...@aol.com> wrote in message news:3bebcd47_2@dnews...
Why not Draw the Bitmap in the OnTerminate event ?
Thanks for the tip. It's a bit sketchy on details, though. I'm assuming the
Dormant and FreeImage are to go in the child thread, after it has finished
drawing and before it terminates--thus forcing it to wait, as you say, so
everything is in place before termination. Please write back to confirm or
deny.
I don't think attempts to share the bitmap are a problem in my case, as the
main thread doesn't access the bitmap once starting the child thread, and
finishes using the bitmap before it starts the next one.
I originally created the bitmap within the child thread and passed it back
as via ReturnValue; the main thread freed it when done with it. I abandoned
that for fear that the bitmap was somehow subject to being overwritten once
the child thread terminated, but I guess there's no reason to think so.
Yours,
Elliott
Nils <n.h...@quicknet.nl> wrote in message news:3bec7b14_2@dnews...
Indeed the Dormant and FreeImage go into the child thread, but please just
try it first. All I know is that I had these white squares too for a while,
and could not at all figure out where they came from. I completely re-wrote
the engine then, and added above, as well as better syncrhonisation.
Another detail could be the loading of your bitmap. How did you implement
that? With the "LoadFromFile" procedure? It could well be that you have to
switch that to "LoadFromStream" and create the stream beforehand, with
TFileStream.Create(Filename, accessbits).
I cannot tell you *exactly* what is the cause because I rewrote everything
from scratch after spending a week on searching, implementing all above, and
then it suddenly worked smoothly.
Nils
Elliott Shevin <she...@aol.com> wrote in message news:3bedef55$1_1@dnews...
Either a library is documented to be threadsafe by design, and
threadsafe in what sense exactly and with what use, or it is not
threadsafe. This is because synchronization issues are such that they
are often very unpredictable, and problems may exist that pop up once in
100 times, or once in 10.000 or pop up only on other machines with
certain configurations and such. Therefore there is not the option to
try and see what does work.
The Delphi VCL is not threadsafe. The win32 level is threadsafe in a
particular sense, and this is documented.
Joris
Please do not reply private to mail posted in newsgroups or mailing
lists, unless that was agreed upon first.
When posting to newsgroups or mailing lists, please make sure you read
these guidelines first:
http://web.infoave.net/~dcalhoun/nnq/nquote.html
http://www.borland.com/newsgroups/netiquette.html
> The thread is responsible for reading a
> graphic file and drawing to the TBitmap. So far as I know, the thread
> doesn't make any attempt to access the display.
>
> The main thread waits for this thread to end, puts the bitmap on the
> display, then frees that, allocates another TBitmap, and creates and
starts
> the thread again.
>
> People using my program find that after a number of these iterations, the
> screen shows only white instead of one of the bitmaps it should be
> displaying.
I had exactly this problem when I was developing my Image Viewer (free,
including source, on my website).
I found that all that was needed to fix it was judicious use of TBitmap.
Canvas.Lock - eg.
function TBrowserThread.CreateThumbnail(const FileName: string): TBitmap;
var
bmp : TBitmap;
pict : TPicture;
r, br : TRect;
j : TJPEGImage;
m : TFileStream;
isJPeg : boolean;
w, h, c, rw, rh : Integer;
g : TGraphic;
begin
pict := Nil;
j := Nil;
m := Nil;
bmp := TBitmap.Create;
try
try
bmp.Width := fImageList.Width;
bmp.Height := fImageList.Height;
r := Rect (0, 0, bmp.Width, bmp.Height);
IsJpeg := UpperCase (ExtractFileExt (fileName)) = '.JPG';
if isJPeg then
begin
m := TFileStream.Create (fileName, fmOpenRead or fmShareDenyNone);
j := TJPegImage.Create;
j.Scale := jsEighth;
j.LoadFromStream (m);
g := j;
end
else
begin
pict := TPicture.Create;
pict.LoadFromFile (fileName);
g := pict.Graphic;
end;
w := g.Width;
h := g.Height;
br := r;
InflateRect (r, -6, -6);
bmp.Canvas.Lock;
try
DrawEdge (bmp.Canvas.Handle, br, EDGE_RAISED, BF_MIDDLE or
BF_TOPLEFT or BF_BOTTOMRIGHT);
rw := r.Right - r.Left;
rh := r.Bottom - r.Top;
if (w < rw) and (h < rh) then
bmp.Canvas.Draw (r.Left + (rw - w) div 2, r.Top + (rh - h) div 2,
g)
else
begin
if w > h then
begin
c := h * r.Right div w;
r.top := (r.Bottom - c) div 2 + 1;
r.Bottom := r.top + c
end
else
begin
c := w * r.Bottom div h;
r.left := (r.Right - c) div 2 + 1;
r.Right := r.left + c
end;
bmp.Canvas.StretchDraw (r, g)
end
finally
bmp.Canvas.Unlock
end
finally
pict.Free;
j.Free;
m.Free;
end
except
FreeAndNil (bmp);
end;
Result := bmp
end;
Colin
e-mail :co...@wilsonc.demon.co.uk
web: http://www.wilsonc.demon.co.uk/delphi.htm
Posted with XanaNews
> function TBrowserThread.CreateThumbnail(const FileName: string): TBitmap;
ps. I call this from within a thread, to create thumbnails, and add them
to an image list. I use ImageList_Add directly to do this. That's
threadsafe, but using TImageList.Add isn't because it tries to notify the
UI.
You have all wrong thread safe meens you have some kind of synchronization
>access the user interface. I'm doing LoadFromFile under the influence of
>Mike Lishke's GraphicEx library, which enables TPicture to load many
>additional image formats.
>
>Is TPicture.LoadFromFile threadsafe? Can I force a synchronization that
Actually this is the most thread unsafe code since it accesses a global
variable which exists in the main thread scope.
>won't risk a deadlock with the main thread doing a WaitFor?
>I've sent the user who's having the missing JPEG image problem a revised
>copy of my app which applies a DIBNeeded to a TPicture being loaded when
>the TPicture contains a JPEG, in the hope that it will cure it. But I'd
>like to have a sure fix, preferably without having to revert to working
>without a thread.
Do not use loadfromfile. you must know what is the class you must use
and create it inside the thread and then use loadfromstream.
By all meens avoid any Tpicture code this is more work than you would
expect but it is the only way.
regards
Johnnie.
> Do not use loadfromfile. you must know what is the class you must use
> and create it inside the thread and then use loadfromstream.
But since I'm loading from a file anyway, I'll still have to open the file
somehow before performing the LoadFromStream. Will opening and reading the
file as a TFileStream, then doing the LoadFromStream, suffice?
Would a critical section be helpful?
By "which class," please explain. Is this the difference between TBitmap,
TMetaFile, and TIcon? Or is it some other kind of class? And what would the
class be for, say, a PNG image?
Thanks,
Elliott
Ok. The problem goes like this.
Delphi create a list object in memory which is global inside the implementation
section of the Graphics unit. This list holds the currently installed classes and
their file extensions so when ever you use the OpenFromFile function from
TPicture it accesses this global list to find out which is the class that should be
used based on the file extension and if it finds it then procceds to load the file's
data. There is no mechanism to retreive this information your self only the
classes declared in the Graphics unit have access to this list and TPicture
does not give you any meens to get the class out of a file extension or name.
By trying to create any kind of synchronization mechanism you will actually
force your thread to make the loading inside the main thread since the method
you must synchronize is the LoadFromFile which can not be broken into two
parts.
Now for every file type there are usually a class that enables delphi to open
this file and show it on the screen.
Bitmap files is the TBitmap for Metafiles if the TMetafile for Icons is TIcon
and depending of what libraries you actually use there might be more classes
to support other file formats. I order to implement this in a multithread
environment you have two choices.
1) Create your own list mechanism to hold the classes and there file extensions
in such a way that will make it multi thread safe(locking mechanism
synchronizations etc). And then just add every single class to your list.
2) create a huge or small (depending on the number of file formats you are using)
case statement to actually create a class out of a extension and copy it to every
thread you write.
You can use the TFileStream object in order to use the LoadFromStream method,
but you do not need to read the data from it. Take as an example the following
Bitmap loading.
Var
Stream : TFiLieStream;
BMP : TBitmap;
begin
// open the stream.
Stream := TfileStream.Create('MyBitmap.bmp',fmopenread or fmsharedenynone);
// Create the apropriate class.
BMP := TBitmap.Create;
// Load the data into memory
BMP.LoadFromStream(Stream);
end;
Hope this helps better.
Regards
Johnnie.
I experienced the same problem with TPicture.LoadFromFile, but Mike
Lischke's GraphicsEx library solved them. BTW GraphicsEx was free. Still is?
Dunno.
It also has solved the so much discussed "recognition" problem. It has the
"GraphicFromContent" method:
GraphicExClass := FileFormatList.GraphicFromContent(AStream);
It will recognise the correct content (GIF, PNG, etc) from the AStream
automatically and create the correct Graphic class. So you just have to load
a filestream, feed it to this procedure and you're done, never telling what
kind of picture it is. Unfortunately GraphicsEx does not support JPG
directly (at least not my version) so you'll have to catch that one
separately. You can use a construct like:
GraphicExClass := FileFormatList.GraphicFromContent(AStream);
GraphicClass := nil;
if GraphicExClass = nil then begin
GraphicClass := FileFormatList.GraphicFromExtension(Ext);
if GraphicClass = nil then exit;
end;
You'll just have to provide the variable "ext" (file extension)
I've never experienced any threading problems with this method, and I run
about 10 threads in total, all (possibly) using this code.
Nils
http://www.abc-view.com/abcview.html to see it in action
Johnnie <No...@Noware.non> wrote in message news:3bfe34d7$1_1@dnews...
You seem to imply that accessing global stuff is per definition not
thread safe. That I heard before, it seems to be a persistent rumour,
but it is nonsence.
> Delphi create a list object in memory which is global inside the implementation
> section of the Graphics unit.
This is the global stuff? In that case, this particular thing is not a
threadsafety issue. It gets changes only on application initalization
and application cleanup. It is perfectly stable during the course of the
application. Therefore, it may be read from any thread at any time
during the course of the application.
Because that is the only general rule: you should make sure nothing gets
written to while being read or being written to in another thread.
'Nothing' here includes the single variable kinda stuff (including 32bit
variable, though some would dissagree) as well as the bigger parts of
data that determine programme logic.
Not that any of this matters. VCL is not threadsafe, and that's all
there is to it.
Which by itself proves nothing at all. To be sure of threadsafeness on
an try-and-error basis, you'd have to check on dozens of machines in
many dozens of situations and repeat that check millions of times.
Threadsafeness bugs are simply like that, they are unpredictable and can
pop up only once in many times or only on certain machines or in certain
situations. Threadsafeness is either by design, or it is not.
If Mike documented this to be threadsafe the way you use it, than you
can trust it to be threadsafe. Otherwise, you can't.
Joris Van Damme <as.van.da...@planetinternet.be> wrote in message
news:3BFFC4F4...@planetinternet.be...
Perhaps that's why Einstein was able to improve on it.
Nils
Joris Van Damme <as.van.da...@planetinternet.be> wrote in message
news:3C002E15...@planetinternet.be...
I can argue with that, saying that a theory like relativity originated
on a much more philosofical basis than a theory like newton's gravity.
But this is not b.p.d.physics.
Experience had shown me that carefull design and good theory pays off in
terms of faster development, better reliability, better maintainability,
better compatibility with future systems and better extendability. When
threads are concerned, I have experienced this even more important
because of the unpredictable nature of once-in-a-while bugs.
My view on the VCL not being threadsafe the trial-and-error way you
would like it to be is backed up by the frequency of messages in this NG
sayin' stuff like 'oh, image turns up all black or all white once in a
while, what am i doing wrong in this thread'.
That is only my opinion, I do not think it's worth startin' a war.
Furthermore, we are discussing a 'focus' rather than a 'unique way'
since indeed things will always be a bit of both theory and trial. Good
luck.
No it is not by definition thread unsafe but it is a roule to not access
global variables from a thread to avoid headaches. It is true that
you can have read only access from multiple threads to a global
variable but I use it as a general roule "no access what so ever to
any global variables from a thread".
>This is the global stuff? In that case, this particular thing is not a
>threadsafety issue. It gets changes only on application initalization
>and application cleanup. It is perfectly stable during the course of the
>application. Therefore, it may be read from any thread at any time
>during the course of the application.
Ok. Now please tell me what happens when I load packages dynamicall
when there usage is needed and unload them when it is not needed. When
the files are registered and when they are unregistered?
>Because that is the only general rule: you should make sure nothing gets
>written to while being read or being written to in another thread.
>'Nothing' here includes the single variable kinda stuff (including 32bit
>variable, though some would dissagree) as well as the bigger parts of
>data that determine programme logic.
Yep and I can't make sure because there is no synchronization
mechanism around the class list in the graphics unit.
>Not that any of this matters. VCL is not threadsafe, and that's all
>there is to it.
>
Again you give a general information. What you seem to imply
is forget all the VCL if you use threads, just write you own
component library and make sure it is thread safe.
I'm not a computer genius and I can't afford to rewrite
the VCL from scratch in order to make it thread safe.
I'm just trying to find the path with the least cost for me.
Thank you for the info.
Kind regards
Johnnie.
>Hi Colin, Eliott, Johnnie
>
>I experienced the same problem with TPicture.LoadFromFile, but Mike
>Lischke's GraphicsEx library solved them. BTW GraphicsEx was free. Still
>is? Dunno.
>
I'm aware about the existance of this library and it is
not free it has an FNC license which meens that I can
learn from it but if I use it on a commercial application I
have to pay Mike for it. I know it is considered free but
seens I can't afford for the moment to by any library I
can't use it with my software, so I haven't downloaded
yet. I'm hopping that I will be able in a couple of mounths
to afford a purchase and Mikes library is in my list I just
don't know if I'll have enough as it is not in my top priority
list.
Be extra carefull with this, contact Mike for more info.
Regards
Johnnie.
OK.
> to avoid headaches
No headache here.
> > In that case, this particular thing is not a
> >threadsafety issue.
>
> Ok. Now please tell me what happens when I load packages dynamicall
> when there usage is needed and unload them when it is not needed. When
> the files are registered and when they are unregistered?
Correct. I should have mentioned that. In most apps, this will not occur
though, all graphic types will be registered upon app initialization.
Not that it matters, again, any VCL code is to be considered not
threadsafe.
> Yep and I can't make sure because there is no synchronization
> mechanism around the class list in the graphics unit.
Nor around hundreds of other things, nor is the few synchronization
got-added-later in the VCL in fact sufficiently small granulized to be
usefull to even the least demanding multithreaded app designs. Again,
any VCL code is to be considered not threadsafe.
> Again you give a general information.
Is there something wrong with that?
> What you seem to imply
> is forget all the VCL if you use threads, just write you own
> component library and make sure it is thread safe.
It is not needed to rewrite the VCL. The VCL is perfectly fine for the
main app thread. A good multithreaded design in my opinion includes this
main app thread as the 'general manager and ui thread', without it ever
doing any considerable processing.
As to the things left, the actual considerable processing that is to be
done in worker threads, I did indeed imply writing your own stuff,
properly designed with multithreaded use in mind, is just about the only
solution I know of sofar.
> I'm just trying to find the path with the least cost for me.
As are we all. As am I.
Joris
General info again and there is nothing wrong with it.
You have placed your own roules and you follow
them and this is fine with me. I do not beleve that
there is not way to use some VCL components
in threads with out any problems it seems possible
to actually use the graphics classes in a thread as
private data which meens copying forth and back
all the class with out any problems this is a way to
work in threads although it is memory intense.
I know this is not the best way to do things but it
is the only way it can work that I know of and it is
more cost efective than writting my own classes,
for now. In the future I'll probably create my own
library which will have all the abilities I'm interested
in but until then I have to work with what I have.
So general statements like that are not very
helpfull to me. I would prefare more accurate
info and I know that when I'll have a more specific
question then some one here will be able to answer
it. This is what it mutters at the end.
thank you for your time and effort.
Regards
Johnnie.