HOWTO: Avoid Extra Threads with Depersisted Embedded Objects
ID: Q196910
|
The information in this article applies to:
-
Microsoft Visual Basic Learning, Professional, and Enterprise Editions for Windows, version 6.0
SUMMARY
When you depersist an object in Visual Basic, Visual Basic creates a thread
for the object. If the object embeds other objects and the ActiveX .exe is
set to use Thread per Object, Visual Basic creates a thread for each
embedded object within the .exe when the object is depersisted. For objects
embedding other objects, the number of threads created is different from a
non-persisted object. Moving the embedded objects from the ActiveX .exe to
a referenced ActiveX DLL can reduce the number of threads created. This
article demonstrates how to achieve this.
MORE INFORMATION
Visual Basic 6.0 introduces the capability of class persistence, which
enables developers to store a component's properties between instances. A
PropertyBag object makes this functionality possible because it stores or
"persists" the object with the current property values for later retrieval.
You can store the PropertyBag object anywhere that binary data can be
stored, such as a file or database. Subsequently, an application can read
the object back in from or "depersist" the PropertyBag object and use the
object. The property values for the depersisted object are those set prior
to saving the object in the PropertyBag, which can be different from the
object's default properties.
The number of threads created with a depersisted object can differ from a
non-persisted object. If an object embeds other objects and the ActiveX
.exe is set to use Thread per Object (specified in Project Properties), a
depersisted object creates multiple threads when it is depersisted. For
example, under on Windows NT, if an object within an ActiveX .exe that is
set to use Thread per Object and has public properties of class types,
Visual Basic creates the following threads when the object is depersisted:
- One thread for the object.
- One thread for each public property of a class type within the
ActiveX .exe.
For instance, if an ActiveX .exe has three class modules (for example,
Class1, Class2, and Class3) and Class1 exposes two properties of type
Class2 and Class3, three threads are created for each Class1 object that is
depersisted. That is, if you depersist ten Class1 objects, Visual Basic
creates thirty threads, in addition to the threads Visual Basic uses.
If the object is not persisted, Visual Basic just creates one thread for
the object.
You can reduce the number of threads that Visual Basic creates upon
depersisting an ActiveX .exe object by moving the contained classes out of
the ActiveX .exe and into an ActiveX DLL, which the ActiveX .exe
references. By doing so, Visual Basic creates only one thread for the
containing class and the embedded classes are created on the same thread.
The example below demonstrates the difference between having embedded
objects within an ActiveX .exe and having an ActiveX .exe reference objects
within an ActiveX DLL.
Step-by-Step Procedures
Create the ActiveX DLL:
- Create a new ActiveX DLL project in Visual Basic. Class1 is created
by default.
- From the Project menu, click Add Class Module to add a Class (Class2) to
the project.
- Change the Class name of Class1 to Class3.
- Set the Persistable Property of Class3 to 1-Persistable.
- Add the following code to Class3:
Public Class3Prop As Variant
- Set the Persistable Property of Class2 to 1-Persistable.
- Add the following code to Class2:
Public Class2Prop As Variant
- From the Project menu, click Project Properties and change the Project
name to Embedded.
- Create the Embedded.dll by selecting Make Embedded.dll from the File
menu.
- Save changes to the Embedded DLL Project.
Create the ActiveX .exe:
- Create a new ActiveX .exe project. Class1 is created by default.
- From the Project menu, click Project Properties. Change the Project name
to PersistThread.
- Set the Persistable Property of Class1 to 1-Persistable.
- From the Project menu, click References. Make a reference to
Embedded.dll.
- Add the following code to Class1:
Dim m_obj As Class2
Dim m_obj2 As Class3
Private Sub Class_InitProperties()
Set m_obj = New Class2
Set m_obj2 = New Class3
' Normally, some initialization takes place here.
End Sub
Private Sub Class_ReadProperties(PropBag As PropertyBag)
' PropertyBag is detected, so you need to read the objects in.
With PropBag
Set MyObject = .ReadProperty("m_obj")
Set MyObject2 = .ReadProperty("m_obj2")
End With
End Sub
Private Sub Class_WriteProperties(PropBag As PropertyBag)
' Save objects into the PropertyBag.
With PropBag
.WriteProperty "m_obj", m_obj
.WriteProperty "m_obj2", m_obj2
End With
End Sub
Public Property Get MyObject() As Class2
Set MyObject = m_obj
End Property
Public Property Set MyObject(ByVal vNewValue As Class2)
Set m_obj = vNewValue
PropertyChanged "m_obj"
End Property
Public Property Get MyObject2() As Class3
Set MyObject2 = m_obj2
End Property
Public Property Set MyObject2(ByVal vNewValue As Class3)
Set m_obj2 = vNewValue
PropertyChanged "m_obj2"
End Property
- From the Project Menu, click PersistThread Properties. In the Threading
Model Section, select Thread per Object.
- From the File Menu, click Make PersistThread.exe to create
PersistThread.exe.
- Save the Project as PersistThread.vbp.
Create and run a Standard .exe:
- Create a new Standard .exe project in Visual Basic. Form1 is created by
default.
- From the Project menu, click References and click PersistThread.exe to
make a reference to PersistThread.
- Paste the following code into Form1:
Private Sub Form_Load()
Dim pb As New PropertyBag
Dim obj(1 To 10) As Class1
Dim idx As Integer
For idx = 1 To 10
Set obj(idx) = New Class1
obj(idx).MyObject.Class2Prop = "Object " & CStr(idx)
obj(idx).MyObject2.Class3Prop = "Object " & CStr(idx)
pb.WriteProperty "Object" & idx, obj(idx)
Next idx
Stop ' Check number of running threads.
Erase obj 'The server goes away here. No threads are running.
Stop
For idx = 1 To 10
Set obj(idx) = pb.ReadProperty("Object" & idx)
Next idx
Stop ' Check the number of running threads.
End Sub
- Start Windows NT Task Manager and position it so that you can see both
Visual Basic and Task Manager.
- Click the Processes Tab. If you do not have a Threads column, click
Columns from the View menu and click Thread Count.
RESULT: A column appears in Task Manager for the number of threads
that are running within each process.
- Save the project as PersistThreadTester.vbp.
- In Visual Basic, press F5 to run the project. The debugger brings you to
the first Stop statement in the code. Now view PersistThread.exe in Task
Manager, there are 13 threads running for PersistThread.exe.
- In Visual Basic, press F5. The debugger brings you to the second Stop
statement, after the Erase statement. In Task Manager, PersistThread.exe
is no longer running and consequently no threads are running.
- In Visual Basic, press F5. The debugger brings you to the third Stop
statement in the code, after the 10 objects have been depersisted. Task
Manager now displays 13 threads running (under Windows 95 or
Windows 98 you see 11 threads).
This is the optimal case, because the contained classes are within a
referenced ActiveX DLL and the number of threads remained the same for the
depersisted object.
Steps to Reproduce Behavior
These steps demonstrate how the persisted object spawns new threads for
each object it embeds. These steps assume that you have already followed
the previous Step-by-Step Procedures.
- Open the project PersistThread.vbp that you created.
- From the Project Menu, click References and clear the reference to
Embedded.DLL.
- Add two Class Modules (Class2 and Class3) to the project by selecting
Add Class Module from the Project menu.
- Set the Persistable Property of Class3 to 1-Persistable.
- Add the following code to Class3:
Public Class3Prop As Variant
- Set the Persistable Property of Class2 to 1-Persistable.
- Add the following code to Class2:
Public Class2Prop As Variant
- Make PersistThread.exe and replace the existing file.
- Save the project.
- Open the PersistThreadTester.VBP project.
- Start Windows NT Task Manager and position it so that you can see
both Visual Basic and Task Manager.
- Click the Processes tab. If you do not have a Threads column, click
Columns from the View menu and click Thread Count.
RESULT: A column appears in Task Manager for the number of threads
that are running within each process.
- Save the project as PersistThreadTester.vbp.
- In Visual Basic, press F5 to run the project. The debugger brings you
to the first Stop statement in the code. Now view PersistThread.exe in
Task Manager, there are 13 threads running for PersistThread.exe.
NOTE: The results are the same as the previous time.
- In Visual Basic, press F5. The debugger brings you to the third Stop
statement in the code, after the 10 objects have been depersisted.
Looking at Task Manager, you see that there are 33 threads running, as
compared to 13 when you used a referenced ActiveX DLL for the embedded
objects (under Windows 95 or Windows 98 you will see 31 threads).
If you are looking to optimize the number of running threads, you can see
using a referenced ActiveX DLL is optimal.
(c) Microsoft Corporation 1998, All Rights Reserved.
Contributions by David Bradley, Microsoft Corporation.
REFERENCES
Visual Basic Help, version 6.0; search on: "Class Persistence"
For a sample on persistence, please see the following article in the
Microsoft Knowledge Base:
Q187299
: SAMPLE: Persist.exe Persists Class Objects with VB6
Keywords : kbole kbActiveX kbCOMt kbDLL kbPersistSt kbThread kbVBp600 kbGrpVB
Version : WINDOWS:6.0
Platform : WINDOWS
Issue type : kbhowto
|