Microsoft KB Archive/196910

= How To Avoid Extra Threads with Depersisted Embedded Objects =

Article ID: 196910

Article Last Modified on 6/29/2004

-

APPLIES TO


 * Microsoft Visual Basic 6.0 Learning Edition
 * Microsoft Visual Basic 6.0 Professional Edition
 * Microsoft Visual Basic 6.0 Enterprise Edition

-



This article was previously published under Q196910



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 or Windows 2000, 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 following example 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

</li> From the Project menu, click Project Properties and change the Project name to Embedded.</li> Create the Embedded.dll by selecting Make Embedded.dll from the File menu.</li> Save changes to the Embedded DLL Project.</li></ol>

Create the ActiveX .exe:

<ol> Create a new ActiveX .exe project. Class1 is created by default.</li> From the Project menu, click Project Properties. Change the Project name to PersistThread.</li> Set the Persistable Property of Class1 to 1-Persistable.</li> From the Project menu, click References. Make a reference to Embedded.dll.</li>  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

</li> From the Project Menu, click PersistThread Properties. In the Threading Model Section, select Thread per Object.</li> From the File Menu, click Make PersistThread.exe to create PersistThread.exe.</li> Save the Project as PersistThread.vbp.</li></ol>

Create and run a Standard .exe:

<ol> Create a new Standard .exe project in Visual Basic. Form1 is created by default.</li> From the Project menu, click References and click PersistThread.exe to make a reference to PersistThread.</li>  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

</li> Start Windows NT or Windows 2000 Task Manager and position it so that you can see both Visual Basic and Task Manager.</li> <li>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.</li> <li>Save the project as PersistThreadTester.vbp.</li> <li>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 under Windows NT or 15 threads under Windows 2000 running for PersistThread.exe.</li> <li>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.</li> <li>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 under Windows NT, 15 threads under Windows 2000, or 11 threads under Win95/98/Me running.</li></ol>

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.

<ol> <li>Open the project PersistThread.vbp that you created.</li> <li>From the Project Menu, click References and clear the reference to Embedded.DLL.</li> <li>Add two Class Modules (Class2 and Class3) to the project by selecting Add Class Module from the Project menu.</li> <li>Set the Persistable Property of Class3 to 1-Persistable.</li> <li> Add the following code to Class3: Public Class3Prop As Variant

</li> <li>Set the Persistable Property of Class2 to 1-Persistable.</li> <li> Add the following code to Class2: Public Class2Prop As Variant

</li> <li>Make PersistThread.exe and replace the existing file.</li> <li>Save the project.</li> <li>Open the PersistThreadTester.VBP project.</li> <li>Start Windows NT or Windows 2000 Task Manager and position it so that you can see both Visual Basic and Task Manager.</li> <li>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.</li> <li>Save the project as PersistThreadTester.vbp.</li> <li>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 under Windows NT or 15 threads under Windows 2000 running for PersistThread.exe.

NOTE: The results are the same as the previous time.</li> <li>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 under Windows NT or 35 threads under Windows 2000 running, as compared to 13 under Windows NT or 15 under Windows 2000 when you used a referenced ActiveX DLL for the embedded objects (under Windows 95, Windows 98, or Windows Me you will see 31 threads).</li></ol>

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.

<div class="references_section">