On Thu, 20 Nov 2008, Pritpal Bedi wrote:
Hi Pritpal,
> Function Main()
> hb_threadStart( {|| First() } )
> hb_threadStart( {|| Second() } )
> do while .t.
> nKey := inkey( 0.2 )
> if nKey == 27
> exit
> endif
> enddo
> Return nil
> Function First()
> hb_gtInfo( HB_GTI_WINTITLE, 'My First Function' ) // Appln Hangs
> Return nil
> Function Second()
> @ 10,20 SAY 'My Second Function' COLOR 'W+/R' // This works ok
> Return nil
> hb_gtInfo() may be looking GT in another context.
It has nothing to GT context which works perfectly (as far as I know).
Few days ago I sent to this list message which explains why such effects
can apear. Please read it again. Now short reduction.
Do you remembert the problem with locking GT you had?
You were arbitrary unlocking it and I tried to tell you
that the problem is not directly related to GT locking
but it's result of Windows API behavior and GT locking
only exploits it. In Windows _ONLY_ thread which created
windows can process windows messages. It means that if
other thread send blocking message then it will be locked
until the thread which created the window will not process
it. I suggested you to locate all such functions and use
their alternative version which will not lock GT or if such
alternative version does not exist to unlock GT before
calling blocking function or you will have deadlock.
Arbitrary unlocking GT inside hb_gtInfoEx() you made and
accessing GT structure with any protection is not a solution
because it may cause that two threads will operate on the
same structure without any protection what may cause its
corruption and the deadlock problem still exists and will
be exploited when user code will begin to use locks.
Code above is example of such deadlock situation.
Two function: GetWindowText() and SetWindowText() are
blocking functions. If you want to allow setting window
title from other threads then the one which created
the window (just like in you example) then you should
change GTWV[TG] code. If you want to only resolve problem
with deadlock which can appear on internal MS-windows mutext
used to protect window and pGT mutex used to protect our
pGT structure then it's enough to unlock pGT before calling
SetWindowText()/GetWindowText() and then resotre the locks.
F.e. this modification resolves the problem in above exmpale:
static void hb_gt_wvt_SetWindowTitle( PHB_GT pGT, HWND hWnd, const char * title
)
{
LPTSTR text = HB_TCHAR_CONVTO( title );
/* SetWindowText() will block this thread until the thread which
* created window will not process window messages. To allow processing
* window message for thread which is window owner we have to unlock
* the GT so it can access it. Otherwise we will have deadlock.
*/
HB_GTSELF_UNLOCK( pGT );
SetWindowText( hWnd, text );
HB_GTSELF_LOCK( pGT );
HB_TCHAR_FREE( text );
}
static BOOL hb_gt_wvt_GetWindowTitle( PHB_GT pGT, HWND hWnd, char ** title )
{
TCHAR buffer[ WVT_MAX_TITLE_SIZE ];
int iResult;
HB_GTSELF_UNLOCK( pGT );
/* GetWindowText() will block this thread until the thread which
* created window will not process window messages.
*/
iResult = GetWindowText( hWnd, buffer, WVT_MAX_TITLE_SIZE );
HB_GTSELF_LOCK( pGT );
if( iResult > 0 )
{
*title = ( char * ) hb_xgrab( iResult + 1 );
HB_TCHAR_GETFROM( *title, buffer, iResult );
( *title )[ iResult ] = '\0';
return TRUE;
}
*title = NULL;
return FALSE;
}
Add it to GTWVT and update hb_gt_wvt_SetWindowTitle() and
hb_gt_wvt_GetWindowTitle() calls to add pGT as 1-st parameter.
Anyhow it's not very good solution because the problem can return
when user code will use some locks. F.e. thread can lock some user
mutex which will stop the thread which created the window. When
this thread calls SetWindowText() or GetWindowText() then we
have exactly the same deadlock.
So you should create alternate solution which will not lock the
thread or you can keep above modification but you have to document
that HB_GTI_WINTITLE is locking action in GTWV[TG] and user should
resolve the potential deadlock problem in his code himself. F.e.
he should unlock your own mutexes before calling it and then lock
them again.
I do not like it so I prefer unlocking solution but the second
one is also acceptable. It's only important to well document
such actions so user will know about it.
In this case (setting window title) you can resolve the problem
quite easy. It's enough to keep window tile in pWVT variable
(it will eliminate GetWindowText() calls) and call SetWindowText()
only by thread which created the window. You can store thread ID
(HB_THREAD_SELF()) for thread which create window inside pWVT
structure so you can check it.
There is also yet another solution. You can create non HVM thread
which will be used to create all windows and process their message
queues. It will not make any other jobs so it will be always available
and other threads which may call locking windows API function will
not have to worry about deadlock because all locks used by window
owner thread will be known. This also resolve the problem of
automatic window refreshing.
HTH and now you understand what is the problem and why unlocking
GT inside hb_gtInfoeEx() before calling GT method(s) is a hack
which may hide the problem in one particular case but it's not a
real solution. You have to design your code keeping in mind that
in MS-Windows only thread which created window can process window
messages and other threads will be blocked calling functions which
needs as result message processing.
best regards,
Przemek
_______________________________________________
Harbour mailing list
[email protected]
http://lists.harbour-project.org/mailman/listinfo/harbour