Re: [VB6] - Module for working with multithreading.
lowe517, you can't call the methods of an object between threads without marshaling. You can pass the socket handle between threads so you can create an auxiliary object which lives in the thread. See the example.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
lowe517, you can't call the methods of an object between threads without marshaling. You can pass the socket handle between threads so you can create an auxiliary object which lives in the thread. See the example.
Re: [VB6] - Module for working with multithreading.
Dear The trick,
I find that I can do the some work using VBCreatethread, as well as using a private object as your example showed,all I need to do is that I dim an object(cTCPClient) in the threadFunc and after its method calling I free it. the object exists only in the threadfunc, everything seems all right, but is there anything potentially wrong ?
Re: [VB6] - Module for working with multithreading.
Originally Posted by lowe517
Dear The trick,
I find that I can do the some work using VBCreatethread, as well as using a private object as your example showed,all I need to do is that I dim an object(cTCPClient) in the threadFunc and after its method calling I free it. the object exists only in the threadfunc, everything seems all right, but is there anything potentially wrong ?
The main restriction you shouldn't pass an object reference between threads. The other point is you should track the data and synchronize access. The rules are the same if you would work in C/C++.
Re: [VB6] - Module for working with multithreading.
So I'm trying to follow how this all works but it's quite difficult, so sorry if this is a stupid question, but will threads created in this manner terminate normally, when the Thread Proc completes? As in, I can duplicate the handle and use WaitOnSingleObject, and expect it terminate as expected when the thread proc exits?
Re: [VB6] - Module for working with multithreading.
Originally Posted by fafalone
So I'm trying to follow how this all works but it's quite difficult, so sorry if this is a stupid question, but will threads created in this manner terminate normally, when the Thread Proc completes? As in, I can duplicate the handle and use WaitOnSingleObject, and expect it terminate as expected when the thread proc exits?
When you use vbCreateThread it's the same like you use CreateThread-API. It returns a Win32 handle you can pass to other APIs. And yes the threads terminate normally.
It only seems to happen inside WinDbg when I have created two threads. It does not seem to happen outside WinDbg but this may be a timing issue. I have included a screen shot of the stack.
Perhaps you have some idea what is happening?
EDIT - I take it back. It does happen outside WinDbg
EDIT EDIT - It does happen outside WinDbg but not reliably. Sometimes its fine.
Re: [VB6] - Module for working with multithreading.
It may be my fault. I was calling this in the startup for each thread right before vbCreateThread. If I only call it once it seems fine.
Code:
Public Function Initialize() As Boolean
10 On Error GoTo errorHandler
Dim bIsInIDE As Boolean
20 Debug.Assert MakeTrue(bIsInIDE)
40 If Not bIsInIDE Then
50 If Not tLockMarshal.bIsInitialized Then
60 writeAgentLog "INFORMATION - Initialized Marshal lock"
70 InitializeCriticalSection tLockMarshal.tWinApiSection
80 tLockMarshal.bIsInitialized = True
90 End If
100 If Not tLockHeap.bIsInitialized Then
110 writeAgentLog "INFORMATION - Initialized heap lock"
120 InitializeCriticalSection tLockHeap.tWinApiSection
130 tLockHeap.bIsInitialized = True
140 End If
150 hModule = App.hInstance
160 pVBHeader = GetVBHeader()
170 If pVBHeader = 0 Then GoTo CleanUp
180 ModifyVBHeader AddressOf FakeMain
190 hHeadersHeap = HeapCreate(0, 0, 65536)
200 If hHeadersHeap = 0 Then GoTo CleanUp
210 End If
220 lTlsSlot = TlsAlloc()
230 If lTlsSlot = TLS_OUT_OF_INDEXES Then GoTo CleanUp
' // Main thread already initialized
240 TlsSetValue lTlsSlot, ByVal 1&
250 Initialize = True
CleanUp:
300 If Not Initialize Then
'writeAgentLog "Calling uninitialize"
310 Uninitialize
320 End If
330 Exit Function
End Function
Re: [VB6] - Module for working with multithreading.
Thanks a lot for the multithreading files.
However, I have a problem with it:
It works only when compiling to system code
When compiling to p-code the exe it seems hangs when the thread is started and the crashses (the window just closes).
I have a large project and when compiling it to systerm code I get a linker error:
........Form....frm(-22483) : fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'E:\8783\vc98\p2\src\P2\main.c', line 494)
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information
I have no idea how to solve that.
Any chance the multithreading will work with p-code?
Re: [VB6] - Module for working with multithreading.
There is no way to implement in-proc multi-threading with p-code compiled modules either using this submission or any other one because the p-code interpreter is not thread safe.
In your case if you *have* to use in-proc multi-threading (this or other impl) there is no other way for this than to fix the internal compiler error by figuring out what is causing it in your VB6 project.
It is either targeting p-code and forget about in-proc multi-threading, fix internal compiler error and use in-proc multi-threading or try using ActiveX EXEs i.e. out-of-proc multi-threading w/ p-code.
Re: [VB6] - Module for working with multithreading.
Thanks for the quick reply.
It seems I have to find out what line is causing the linker error.
Or does this work with an active x dll in p code?
Is there a thread about difference between p-code and native code?
E.g.
For i = 0 to ubound(List())
Next
hangs in the for loop when compiling to native code and List() is empty, but with compiled to p-code it works fine.
When On Error Resume Next is used
Other such known differences?
Last edited by Chris_G33; Mar 25th, 2023 at 10:00 AM.
Re: [VB6] - Module for working with multithreading.
Originally Posted by Chris_G33
Other such known differences?
Why do you think this is a known difference? Is there a list of known differences you are looking at which has this one listed there?
Better ask in the main forum if someone (who cares about these differences) knows anything might chime in because this thread is about multi-threading.
Re: [VB6] - Module for working with multithreading.
Originally Posted by SuperDre
Why would you want compiled to p-Code in the first place? what's the benifits over compiling to native code (as p-code is a lot slower as native)?
P-Code:
- Smaller files
- im my experience not really much slower, maybe some %
- faster compiling
- I had problems with native code some years ago (cant remember details) and with p-code it was working fine.
And now I have that damn compiler error, still after 2 hours changing code etc.
Maybe the compiler has a problem in a form with more than ~49000 lines.
Re: [VB6] - Module for working with multithreading.
Originally Posted by fafalone
Checked more samples and it's all over the map... pcode is ranging from half the size, to very close (most common), to 4 bigger
I think it's safe to say that, when we compile "code-only" Projects (like e.g. Ax-Dlls),
PCode produces "roughly half the size" compared to NativeCode.
In your 1:1 cases there's probably "a lot of Bitmaps and Icons" embedded
(coming from visual-resource-parts as *.frx or *.ctx,
making the PCode-savings insignificant compared to the resource-volume)...
And your case where PCode is 4 times larger might be related to Typelib-embedding?
Never investigated that, but PCode might embed a referenced *.tlb in its entirety -
whereas native-compiles "embed only the needed parts of a typelib"?
Re: [VB6] - Module for working with multithreading.
I now got one project working.
Thanks again for this great piece of code.
My exe is now 16 MB (native code) instead of 6 MB (p code).
My other project with the "fatal error C1001: INTERNAL COMPILER ERROR": I moved some routines to another bas file. Now it compiles. But the exe just quits after some seconds. I need to investigate further.
(It seems for the line number a signed 16bit integer, as the line number of my error message was Form....frm(-22483)), though the line number was -22483 + 65536 = 43053.)
Re: [VB6] - Module for working with multithreading.
The linker can remove unused code from executables (native-code) whenas P-code saves everything. So if you use an universal standard module with bunch of functions and use few ones the native code can have smaller size.
Re: [VB6] - Module for working with multithreading.
Originally Posted by Chris_G33
I now have the problem that my exe sometimes terminates when a thread ends.
Any idea how to solve that?
You have to *manually* release global state i.e. private and public variable of Object and String type in a .bas module has to be cleared (set to Nothing or vbNullString) in ThreadProc before calling CoUninitialize and subsequenctly returning execution to OS.
This is practically impossible with static "local" variables in procedures so in-proc mutli-threading in VB6 is doomed unless threaded lightly by the app. developers themselves (take care of every wrinkle introduced).
Another thing which might help if you are using Ax DLL for the in-proc is to enable Retained in Memory in project settings though I wouldn't hold my breath.
Re: [VB6] - Module for working with multithreading.
Originally Posted by wqweto
You have to *manually* release global state i.e. private and public variable of Object and String type in a .bas module has to be cleared (set to Nothing or vbNullString) in ThreadProc before calling CoUninitialize and subsequenctly returning execution to OS.
This is practically impossible with static "local" variables in procedures so in-proc mutli-threading in VB6 is doomed unless threaded lightly by the app. developers themselves (take care of every wrinkle introduced).
cheers,
</wqw>
Thanks for the answer.
But, can you please clarify this.
1. clear private strings and objects, ok. Why only in bas modukes, but not in Forms?
2. public strings:
Do i have to clear them only when they are set/modified in a thread? Or when they are only accessed by reading them, too?
Re: [VB6] - Module for working with multithreading.
I suppose (according to your log) you call Uninitialize when you have worked threads. So you should either wait until the threads end or don't call Uninitialize at all.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
I suppose (according to your log) you call Uninitialize when you have worked threads. So you should either wait until the threads end or don't call Uninitialize at all.
Re: [VB6] - Module for working with multithreading.
When I need to transfer data in strings from a thread to the main thread, i see these options:
1. a public String variable in a form
2. a textfield control in a form
3. a string with fixed length
4. a public string, which I prealloc in the main thread e.g. with mystring = String$(1000, 0) and in the the thread I copy a local string to that string using the StrPtr
Re: [VB6] - Module for working with multithreading.
Originally Posted by Chris_G33
When I need to transfer data in strings from a thread to the main thread, i see these options:
1. a public String variable in a form
2. a textfield control in a form
3. a string with fixed length
4. a public string, which I prealloc in the main thread e.g. with mystring = String$(1000, 0) and in the the thread I copy a local string to that string using the StrPtr
Is this correct?
See AsynchDispMethodCall. It accepts a callback method which is called when the method is done. You can see the examples there are many callback examples.
Re: [VB6] - Module for working with multithreading.
I now have another issue/question.
The created threads are working fine multithreadwise.
But not the main thread and the created threads. Only one of the is active, either the main thread or the created threads.
e.g.
Code:
Sub Test()
Dim i As Long
vbCreateThread 0, 0, AddressOf MyThread1, 0, 0, 0
vbCreateThread 0, 0, AddressOf MyThread2, 0, 0, 0
for i = 0 to 10
sleep 100
next
End Sub
MyThread1 and MyThread2 are not started after calling vbCreateThread, they are called when the procedure Test is finished and the main thread gets idle. Of course, I could add some DoEvents, but then still, either the main thread OR the created threads are executed.
Why is that so?
Is there a way to have full multithreading here, too?
Re: [VB6] - Module for working with multithreading.
You have a bug with marshaling. You can't just access to an object from an arbitrary thread. You should use marshaling always to avoid the bugs in future. The behavior of your code is explained by the fact that you call Form1.Text2.Text = "Thread 1: " & CStr(GetCurrentThreadId()) & vbNewLine and Form1.Text3.Text = "Thread 2: " & CStr(GetCurrentThreadId()) & vbNewLine which just call SetWindowText that calls SendMessage WM_SETTEXT. SendMessage waits until the window process the message in main thread.
Re: [VB6] - Module for working with multithreading.
Originally Posted by The trick
You have a bug with marshaling. You can't just access to an object from an arbitrary thread. You should use marshaling always to avoid the bugs in future. The behavior of your code is explained by the fact that you call Form1.Text2.Text = "Thread 1: " & CStr(GetCurrentThreadId()) & vbNewLine and Form1.Text3.Text = "Thread 2: " & CStr(GetCurrentThreadId()) & vbNewLine which just call SetWindowText that calls SendMessage WM_SETTEXT. SendMessage waits until the window process the message in main thread.
Thanks for your anwer.
I tried with
MultiThreading.EnablePrivateMarshaling True
but no change.
What do I have to change in my example code? I don't know mashalling in VB6.
Re: [VB6] - Module for working with multithreading.
Originally Posted by Chris_G33
Thanks for your anwer.
I tried with
MultiThreading.EnablePrivateMarshaling True
but no change.
What do I have to change in my example code? I don't know mashalling in VB6.
So, if do not do GUI stuff it should work.
You should use Marshal/Unmarshal functions to pass an object between threads (read the description). You can't use your code because to set form's caption you should message pump in the form's thread. The same behavior you will see in any other language.
Re: [VB6] - Module for working with multithreading.
Hello Trick,
I wanted to use atlsimpleobjforvb simpleobject from Atlsimpleobjdeno atl project using CreateActiveXObjectInNewThread2 of modMultiThreading2.bas as follows by adding atl dll project thru references:
Code:
Dim x As ATLSIMPLEOBJDENOLib.atlsimpleobjforvb
Private Sub Command1_Click()
Dim cObj As Object
Dim asyncid As Long
Set cObj = CreateActiveXObjectInNewThread2("ATLSIMPLEOBJDENOLib.atlsimpleobjforvb", , asyncid) 'fails with Invalid procedure call or argument error
cObj.method1
End Sub
Private Sub Form_Load()
modMultiThreading.Initialize
End Sub
Private Sub Form_Unload(Cancel As Integer)
modMultiThreading.Uninitialize
End Sub
when I add atl project thru references to vb st exe projectI run the project I get msgbox with the following error.
Re: [VB6] - Module for working with multithreading.
Originally Posted by smkperu
Hello Trick,
I wanted to use atlsimpleobjforvb simpleobject from Atlsimpleobjdeno atl project using CreateActiveXObjectInNewThread2 of modMultiThreading2.bas as follows by adding atl dll project thru references:
Code:
Dim x As ATLSIMPLEOBJDENOLib.atlsimpleobjforvb
Private Sub Command1_Click()
Dim cObj As Object
Dim asyncid As Long
Set cObj = CreateActiveXObjectInNewThread2("ATLSIMPLEOBJDENOLib.atlsimpleobjforvb", , asyncid) 'fails with Invalid procedure call or argument error
cObj.method1
End Sub
Private Sub Form_Load()
modMultiThreading.Initialize
End Sub
Private Sub Form_Unload(Cancel As Integer)
modMultiThreading.Uninitialize
End Sub
when I add atl project thru references to vb st exe projectI run the project I get msgbox with the following error.