Re: Serious GDI Multithreading bug while printing to metafiles
- From: "Christian Kaiser" <bchk@xxxxxx>
- Date: Fri, 11 Apr 2008 08:13:52 +0200
I would expect that GDI calls done to DIFFERENT DCs are thread-safe.
There's nothing the threads have in common.
The problem appears only when recording into metafiles in parallel. Of
course it's a threading issue - inside GDI.
Christian
"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospam> wrote in
message news:36A2769A-9A2A-439E-9FB5-DE4D8BE303F4@xxxxxxxxxxxxxxxx
There's nothing thread safe about GDI calls.
Is there a thread synchronization issue there?
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
"Christian Kaiser" <bchk@xxxxxx> wrote in message
news:eWIGx4wmIHA.4504@xxxxxxxxxxxxxxxxxxxxxxx
Customers of ours reported a bug in our software that causes
metafiles
to be incorrect.
We now reduced the bug using the appended code, which is run by
multiple threads simultaneously. The code opens a printer DC, uses
that as reference DC for a new metafile DC, creates/selects a font,
draws a text, deselects and destroys the font, then destroys the
metafile DC and the printer DC. Trivial code in my eyes.
This should result in repeated calls like (decompiled to C code
using
EMF decoder, special thanks to Feng Yuan who makes that very easy):
...
hObj[1]=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
SelectObject(hDC, hObj[1]);
const int Dx_5[]={ 5 };
ExtTextOutW(hDC, 4,4,0,NULL,L"x",1,Dx_5);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
DeleteObject(hObj[1]);
hObj[1]=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
SelectObject(hDC, hObj[1]);
const int Dx_6[]={ 5 };
ExtTextOutW(hDC, 5,5,0,NULL,L"x",1,Dx_6);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
DeleteObject(hObj[1]);
hObj[1]=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
SelectObject(hDC, hObj[1]);
const int Dx_7[]={ 5 };
ExtTextOutW(hDC, 6,6,0,NULL,L"x",1,Dx_7);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
DeleteObject(hObj[1]);
...
and most of the times it does.
When run in multiple concurrent threads, however, some of the
repetitions miss some GDI calls:
...
hObj[1]=CreateFont(-10,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
SelectObject(hDC, hObj[1]);
const int Dx_62[]={ 5 };
ExtTextOutW(hDC, 61,61,0,NULL,L"x",1,Dx_62);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
DeleteObject(hObj[1]);
const int Dx_63[]={ 5 };
ExtTextOutW(hDC, 62,62,0,NULL,L"x",1,Dx_63);
const int Dx_64[]={ 5 };
ExtTextOutW(hDC, 63,63,0,NULL,L"x",1,Dx_64);
SelectObject(hDC, GetStockObject(DEVICE_DEFAULT_FONT));
const int Dx_65[]={ 5 };
ExtTextOutW(hDC, 64,64,0,NULL,L"x",1,Dx_65);
const int Dx_66[]={ 5 };
ExtTextOutW(hDC, 65,65,0,NULL,L"x",1,Dx_66);
const int Dx_67[]={ 5 };
ExtTextOutW(hDC, 66,66,0,NULL,L"x",1,Dx_67);
const int Dx_68[]={ 5 };
ExtTextOutW(hDC, 67,67,0,NULL,L"x",1,Dx_68);
const int Dx_69[]={ 5 };
ExtTextOutW(hDC, 68,68,0,NULL,L"x",1,Dx_69);
const int Dx_70[]={ 5 };
ExtTextOutW(hDC, 69,69,0,NULL,L"x",1,Dx_70);
const int Dx_71[]={ 5 };
ExtTextOutW(hDC, 70,70,0,NULL,L"x",1,Dx_71);
const int Dx_72[]={ 5 };
ExtTextOutW(hDC, 71,71,0,NULL,L"x",1,Dx_72);
const int Dx_73[]={ 5 };
ExtTextOutW(hDC, 72,72,0,NULL,L"x",1,Dx_73);
...
This happens at least in Windows XP and in Vista.
Strange is, the CreateFont(), SelectFont(), ..., DeleteFont() is
being
executed in the DC correctly, and the DC state reflects this (we
can
see this in our application, which uses the selected font for some
layouting - these calculations are correct). The GDI calls are just
not stored in the metafile. There is no failure in CreateFont or
SelectFont (I left out of the checking code in the demonstration
code
below, for clarity reasons).
Next astonishing thing is that setting the ProcessAffinityMask to
one
processor does not help. It still happens - this, for me, was
really
unexpected.
When the code below is executed multiple times, it should create
similar EMF files - but they all vary in size as indication there's
something going wrong. Looking into them, it can be seen that there
are a lot of missing records.
Serializing the whole sequence is a possible solution (a part, for
example, only CreateFont/SelectFont does not help), but scales
extremely bad with multiple processors ;-(. Especially when the GDI
calls are not so easily locateable, but all over thousands of code
lines.
Is a workaround known? This is a serious problem in multithreaded
printing (using metafiles).
Christian
------------------------------
PRINTDLG pd = {0};
TCHAR szFile[MAX_PATH];
_stprintf(szFile,"test_%08x.emf",::GetCurrentThreadId());
pd.lStructSize = sizeof(pd);
pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
::PrintDlg(&pd);
RECT rcPage = {0,0,10000,10000};
HDC hMetaDC = ::CreateEnhMetaFile(pd.hDC,szFile,&rcPage,"Hallo");
for (int i = 0; i < 2000; ++i)
{
HFONT hFont = ::CreateFont(
-10,
0,
0,
0,
0,
0,
0,
0,
ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
0,
"Arial");
HFONT hOldFont = SelectFont(hMetaDC,hFont);
::ExtTextOut(hMetaDC,
i,
i,
0,
NULL,
"x",
1,
NULL);
SelectFont(hMetaDC,hOldFont);
DeleteFont(hFont);
}
HENHMETAFILE hEMF = ::CloseEnhMetaFile(hMetaDC);
::DeleteObject(hEMF);
::DeleteDC(pd.hDC);
.
- Follow-Ups:
- Re: Serious GDI Multithreading bug while printing to metafiles
- From: Christian Kaiser
- Re: Serious GDI Multithreading bug while printing to metafiles
- References:
- Serious GDI Multithreading bug while printing to metafiles
- From: Christian Kaiser
- Re: Serious GDI Multithreading bug while printing to metafiles
- From: Mark Salsbery [MVP]
- Serious GDI Multithreading bug while printing to metafiles
- Prev by Date: Re: Serious GDI Multithreading bug while printing to metafiles
- Next by Date: gdipcreateeffect
- Previous by thread: Re: Serious GDI Multithreading bug while printing to metafiles
- Next by thread: Re: Serious GDI Multithreading bug while printing to metafiles
- Index(es):
Relevant Pages
|
Loading