Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Multithreading... help!

17 views
Skip to first unread message

Giuseppe Antonelli

unread,
Nov 8, 2001, 12:51:46 PM11/8/01
to
Hello!
I am writing multithreading server in VO25b-3 on Win2000. After several
messages received, application die without to leave any kind of information
or error messages. If I remove instructions abuot counters (active threads
and messagge received) application work fine.
WHAT I AM WRONG ???

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

Ginny Caughey

unread,
Nov 8, 2001, 2:01:03 PM11/8/01
to
Giuseppe,

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...

Giuseppe Antonelli

unread,
Nov 9, 2001, 9:21:33 AM11/9/01
to
Hi Ginny,
Thank you very much for your help, also by Valter side (my boss!). I applied
your suggestions and now everithing work fine! If we will have another
occasion to meet us, I will present you a little thing from my country
(Italy). I said another because I already met you last March at Devfest 2001
in London. I followed your speaking in the handheld computer session.
However, in this solution I have big problem: how to say to the main thread
(dialog), to show a message (for example a user name who is connected or
some other general message) from a worker thread? I thought to use a lParam
argument in PostMessage API call with some code and on Dispatch method get
code and find it in a table, the related message description. Is this a
suiteble (good) solution? I would like to know your opinion (solution?) from
the high of your experience.

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...

Ginny Caughey

unread,
Nov 9, 2001, 2:35:17 PM11/9/01
to
Hi Giuseppe,

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...

0 new messages