Ciao
Giuseppe
// ************************************************************
STRUCTURE ThrListenPar
//
// ThreadListenPar
//
MEMBER MsgReceivedCtrl AS PTR
MEMBER ActThreadsCtrl AS PTR
STRUCTURE ThrConverPar
//
// ThreadConverPar
//
MEMBER MsgReceivedCtrl AS PTR
MEMBER ActThreadsCtrl AS PTR
// ************************************************************
METHOD StartButton CLASS Srv
// Here server start
// Alloc
LPar := MemAlloc(_SizeOf(ThrListenPar))
// Regis
RegisterKid(@LPar.MsgReceivedCtrl, 1, FALSE)
RegisterKid(@LPar.ActThreadsCtrl, 1, FALSE)
// both oDCMsgReceived and oDCActiveThreads are FixedText controls
LPar.MsgReceivedCtrl := PTR(_CAST, SELF:oDCMsgReceived)
LPar.ActThreadsCtrl := PTR(_CAST, SELF:oDCActiveThreads)
// Run thread
hThread := CreateVOThread(NULL, 0, @ThrListen(), LPar, 0, @nId)
CloseHandle(hThread)
// *END* StartButton
// ************************************************************
FUNCTION ThrListen(nLPar AS DWORD) AS INT PASCAL
LOCAL LPar AS ThrListenPar
LOCAL CPar AS ThrConverPar
LOCAL cThrId AS STRING
LOCAL hThreadC AS PTR
LOCAL nIdC AS DWORD
LPar := nLPar
//
cThrId := StrZero(GetCurrentThreadId(),4)
WHILE TRUE
// Accept()
//
CPar := MemAlloc(_SizeOf(ThrConverPar))
// Regis
RegisterKid(@CPar.ActThreadsCtrl, 1, FALSE)
RegisterKid(@CPar.MsgReceivedCtrl, 1, FALSE)
//
CPar.ActThreadsCtrl := LPar.ActThreadsCtrl
CPar.MsgReceivedCtrl := LPar.MsgReceivedCtrl
//
hThreadC := CreateVOThread(NULL, 0, @ThrConver(), CPar, 0, @nIdC)
CloseHandle(hThreadC)
CollectForced() // *DEBUG*
END
RETURN 0
// ************************************************************
FUNCTION ThrConver(nCPar AS DWORD) AS INT PASCAL
LOCAL CPar AS ThrConverPar
LOCAL cThrId AS STRING
LOCAL oActThreads AS FixedText
LOCAL oMsgRecv AS FixedText
//
CPar := nCPar
oActThreads := OBJECT(_CAST, CPar.ActThreadsCtrl)
oMsgRecv := OBJECT(_CAST, CPar.MsgReceivedCtrl)
// Id thread
cThrId := StrZero(GetCurrentThreadId(),4)
//
EnterCriticalSection(@cs)
++gnActiveThreads
oActThreads:Caption := AsString(gnActiveThreads)
++gnMsgReceived
oMsgRecv:Caption := AsString(gnMsgReceived)
LeaveCriticalSection(@cs)
...
// SOME WORK HERE
...
//
EnterCriticalSection(@cs)
--gnActiveThreads
oActThreads:Caption := AsString(gnActiveThreads)
LeaveCriticalSection(@cs)
//
UnregisterKid(@CPar.ActThreadsCtrl)
UnregisterKid(@CPar.MsgReceivedCtrl)
MemFree(CPar)
RETURN 0
I have also run into problems updating GUI controls from worker threads. I don't
know if this is a VO problem, or more likely, simply a Windows problem since the
GUI part of the Win32 API is not thread safe. The only solution I have found is
to use PostMessage from the worker threads to the window and then write a
Dispatch method for the window that knows what these special messages mean and
handles the controls. This gets around the problem because Windows guarantees
that the thread that created a window (or control) will be the active thread
when a message for it is delivered. It also simplifies the code since you can
thn get rid of the RegisterKID and Object(_Cast) type stuff. You just have to
pass the handle to the main window to each thread and come up with some system
of using PostMessage to convey all the info you need to update the controls.
HTH,
Ginny
"Giuseppe Antonelli" <valt...@tin.it> wrote in message
news:SCzG7.25751$zl4.7...@news2.tin.it...
Ciao
Giuseppe
PS. Sorry for my bad english, sometimes I forgot also how to speak in
italian...
"Ginny Caughey" <ginny....@wasteworks.com> ha scritto nel messaggio
news:9seki3$52n$1...@suaar1ac.prod.compuserve.com...
Yes, you have the right idea. I use defines like this:
DEFINE MSG_StartStop := WM_USER+10
DEFINE MSG_GettingData := WM_USER+11
DEFINE MSG_Polling := WM_USER+12
DEFINE MSG_Sampling := WM_USER+13
DEFINE MSG_ScaleError := WM_USER+14
DEFINE ScaleStarted := 1
DEFINE ScaleStopped := 0
The threads send messages like this:
// Update status bar with scale started text
PostMessage(pInfo.hWnd, MSG_StartStop, pInfo.ScaleNumber, ScaleStarted)
(where pInfo is the parameter structure passed to the threaded function)
Then in my dispatch method for the dialog that manages the multiple threads I
this sort of code:
IF oEvent:uMsg == MSG_StartStop
SELF:Parent:StatusBar:TemporaryText := "Scale
"+NTrim(oEvent:wParam)+iif(oEvent:lParam != ScaleStarted, ;
" started", " stopped")
ELSEIF oEvent:uMsg == MSG_GettingData
SELF:Parent:StatusBar:TemporaryText := "Getting data for scale
"+NTrim(oEvent:wParam)
ELSEIF oEvent:uMsg == MSG_Polling
SELF:Parent:StatusBar:TemporaryText := "Polling for a vehicle on scale
"+NTrim(oEvent:wParam)
ELSEIF oEvent:uMsg == MSG_Sampling
SELF:Parent:StatusBar:TemporaryText := "Sampling for maximum weight on
scale "+NTrim(oEvent:wParam)
ELSEIF oEvent:uMsg == MSG_ScaleError
SELF:Parent:StatusBar:TemporaryText := "Error reading scale
"+NTrim(oEvent:wParam)
ENDIF
Anyway, you have the idea already, and a table would work better if I had lots
of different messages to manage.
BTW your English is just fine, and I do remember meeting you last year. Will you
be at DevFest next year? I will be doing a session on multithreading - but I
don't think you need it now. <g> Another tip you might need is to be sure any
loops in your threads have small Sleep calls in them so the GUI thread gets
enough time slices. You may also want to decrease the priority of the worker
threads if the GUI isn't responsive enough. And remember that you can use
PostThreadMessage from the main thread if you need to tell any worker threads to
shut down. (Just be sure the worker thread has a message pump looking for
WM_CLOSE for example.)
Ginny
"Giuseppe Antonelli" <valt...@tin.it> wrote in message
news:NDRG7.30018$zu5.1...@news1.tin.it...