Advanced COM COMScriptThread object
ProgID-s and ClassID, Members reference

Overview

The COMScriptThread object like COMThread object allows the application to execute separate threads. Unlike COMThread the COMScriptThread is especially designed to run scripts in separate threads. This makes it much easier to use and leaves place for features that allow full compatibility of the code that depends on it with all the supported platforms. For example with COMThread object you need a COMApartment object in order to run script in a separate thread, but on Windows CE based devices COM system does not support single threaded apartments which makes COMThread not applicable for scripts and many other COM objects on these devices. COMScriptThread does not have these set backs, but of course there is a price - much thinner communication with the thread, applicable for scripts only, strictly defined data exchange technique. 

Therefore the COMScriptThread object is best for all the scenarios where it will do the job. Also it requires very little learning efforts, no deep COM knowledge and thus can be used by any developer. 

How it works - lifecycle

The COMScriptThread object itself is the thread controller and also holds a data dictionary/collection object accessible for the both sides - the application that creates the thread and the script running in the thread.

The scheme above illustrates the life cycle of the COMScriptThread object. Note that in case of ASP application, for example, everything displayed there may happen in different pages and during the processing of different requests. For example the application may keep the object in the Application (or Session) and perform actions in different ASP pages of the applications. And this is the main purpose of this component. The wait actions are optional, but are in fact needed in almost any situation as the application cannot be sure that the last operation is completed. In fact the Wait method and the Busy property implement almost the same functionality, but Wait method waits the specified timeout period the thread to complete whatever it is doing, while Busy returns immediately indicating if the thread is currently busy.

Now about the life cycle as whole. As you can see there are two general ways to use the thread:

  • All the work you need to implement can be in the global part of the script and it is executed linearly (in a way very similar to the Windows Script Host scripts or ASP pages). In this case the thread is Started then the application can wait/check for the completion whenever it needs the results from the code running in the thread.
  • The other way to use the thread is to Start it and then when it initializes to Execute one or more routines implemented in the thread's script one or more times. This can be performed multiple times.

If you don't know this yet - the Active Scripts can be used in several different ways. They can be executed sequentially, or started and then placed in stand-by mode and then the routines implemented in them can be called in a way very similar to the way you call methods of a COM object or they can be attached as event sinks to certain event sources. This object allows the first two techniques to be used with the thread's script. However, note that only routines without parameters can be executed (with the Execute method). This is not a problem as the routine can fetch parameters from the Context collection (See Value default property and the Context namespace). 

So, the object starts the thread when the Start method is called and stops it when the Stop method is called. If the thread's script is written to perform its tasks when it is started then the application sticks to the first usage technique and it should wait/check for the completion when it needs the result, then it should stop and release the COMScriptThread object or just stop it if the object will be reused. If the application intends to use the second technique then the script should be written to initialize (perform some global initialization/preparation tasks) and the real task(s) should be implemented as routines in it (they can do quite different things) and then the application can execute these routines asynchronously in the thread (i.e. the Execute schedules the routine execution and returns, then the thread performs it).

The script in the thread

The script in the thread is written as plain script (plain script text). It has certain namespaces supplied by the COMScriptThread object:

Context - The script can access the same collection/dictionary object that is accessible for the outer application through the Value property. For details see the Value property.

Creator - This namespace is available only if the AddCreator property is True before the script is started (which is default). It is a Pack1Creator object. Through it the script can create COM objects, composite objects and so on. It offers better performance when the script creates other objects from the ActiveX pack1 library and also creates them in the same thread.

So the communication between the application and the thread's script is done through the Context collection. The application that creates the thread refers to it through the Value property and the script in the thread through the Context namespace. For example the outer application can do the following to pass a parameter:

o.Value("UserName") = "Joe"
o("DB") = "C:\db.ndb"

Because the Value is a default property it can be omitted. Now the script in the thread can read these values:

Dim userName, dbFile
userName = Context("UserName")
dbFile = Context("DB")

Of course, you should ensure that the values are set before the thread refers to them. For example before it has been started or before  the routine that needs them has been executed.

The reverse operation can be performed too - e.g. the thread's script can set certain values and then the application is able to read them.

The Context collection can be referred at any time, therefore certain values can be used for additional synchronization, for example to indicate progress, intermediate results etc.

Usage

You can see a simple example on the COM threads objects page. In general the script threads are needed when you need to perform time consuming tasks preserving the application ability to respond to the user while the operation is in progress. In Windows Scripting Host (WSH) or Micro Script Host (supplied with ActiveX Pack1 library) the application is usually one script executed sequentially. In this case it may start a thread do some other work and then check/wait for the thread completion when the results from it are needed. In this case you will not need to keep a reference to the COMScriptThread object anywhere else - a variable in the script will do. In Active Server Pages application the application usually consist of more than one pages/scripts executed when the user requests them. The ASP environment offers places where these scripts/pages may save values and objects and preserve them between the separate pages execution - the Application and Session. Thus in case of ASP application the page that creates the COMScriptThread object may save it in the Application or Session, then another page (or the same page) can start the thread, then another page can check/wait for the thread operation to complete and get the results from the Context collection using the Value property. 

Recommendations: In multi-user applications (such as ASP applications) you should be aware of the number of the threads you are running. The application should limit their number - for example for a server application they should be limited according to the memory and CPU resources, in ALP applications their number should be limited as much as possible because you cannot be sure on what kind of machine the application will run. If needed you can easily implement a thread pool and use the first free thread object to execute the new task in it or inform the user that the threads are too much at this moment  and he/she should request the operation later. You can also offer configuration features that allow the number of the thread in pool to be configured etc. Of course the actual way you manage the threads is up to you - some applications may prefer to keep on or more threads initialized and execute routines in their scripts, others will prefer to start threads whenever they need asynchronous operations. The way you choose depends on the work you are doing. For example if there are several different tasks that use similar or the same data, work over one single DB and have something in common in general - then implementing them as routines in one single script and then executing them as needed will produce more compact and effective code then implementing them in separate script files. On contrary if the tasks are too different and over different data and resources, sometimes they could be even fetched from an user specified location - then implementing them as plain sequential scripts will give you better results.

The object will uninitialize, stop the thread when released (e.g. Set o = Nothing if the o is the only variable that holds the object), but note that the work the script does may differ and sometimes may concern resources that need to be properly obtained/released. So, it is recommended to take care to perform proper uninitialization especially if the second technique is used (executing routines) before stopping and releasing the thread, for example by implementing a routine that uninitializes the resources and executing it before stopping/releasing the thread.

About the threading models: By default the object uses multi-threaded COM apartments. Even if the script uses apartment threaded objects to do its work this will not be a problem in almost all the imaginable scenarios. However if because of certain reasons you need to initialize the thread as single-threaded consider the fact that this will not work on Windows CE devices.

Members reference

Name Description
Start Starts the thread with the given script
Execute If the thread is started and in stand-by executes the given routine from the loaded script.
Stop Stops the thread.
Wait Waits for the thread to complete the current operation.
Value Default property: Holds a VarDictionary based collection (dictionary) that is accessible for the both - the application creating the thread and the script in the thread.
Busy Boolean: indicates if the thread is busy.
AddCreator Boolean: If set the running script in the thread will have a Pack1Creator object accessible through the Creator namespace.
LastError String: Contains the last error
MultiThreaded Boolean: If set (default) the thread will be initialized as multithreaded COM apartment.
Priority Integer: The thread priority
Result Variant: The result of the last routine execution (meaningful if the routine is a function)
Success Boolean: Indicates if the last operation was successful (routine execution, thread start)
Timeout Positive integer: Timeout for the internal wait operations.
Active Indicates if the thread is active (Busy or stand by)
newObjects Copyright 2001-2006 newObjects [ ]