| Comparison of the Thread objects in the ActiveX Pack1 (ALP
              run-time library)newObjects ActiveX Pack1 (Active Local Pages run-time library)
              contains two different classes that allow the applications to run
              code in separate thread asynchronously. They are COMThread
              and COMScriptThread. We pose
              them this way: 
                COMThread (alone or in combination with the COMApartment
                  on desktop Windows OS-es) allows various multi-threading and
                  advanced COM techniques to be performed. COMThread often
                  requires deeper COM knowledge from the developer, but allows
                  even scripting applications (such as ASP applications for
                  example) to run tasks asynchronously. We recommend it for
                  usage with quality COM classes - such as components written in
                  C++ optimized for freethreaded COM apartments. On desktops it
                  can be also used (together with COMApartment) with scripts,
                  Apartment threaded classes (written in VB for example) and so
                  on. However there is a set back - on Windows CE based devices
                  COM system does not support singlethreaded apartments and the
                  required marshaling features. Thus any code that initializes
                  threads in single-threaded apartments will not be compatible
                  with these devices!In short: Use this object to call asynchronously
                  methods on free-threaded COM objects (both desktop and CE) or
                  COM objects packed in COMApartments (on desktops only).
COMScriptThread is very easy to use threading tool
                  for scripting. In other words with it only scripts (for
                  example VBScript, JScript) can be executed asynchronously in
                  separate threads. It does not require deep COM knowledge from
                  the developer and does not depend on COM support for
                  single-threaded apartments. This means that it is compatible
                  with both desktop and embedded versions of Windows (e.g.
                  Pocket PC, smartphones etc.). To achieve simplicity and
                  cross-platform compatibility it poses certain limitations -
                  thinner communication between the thread and the application,
                  only scripts can be executed. However the COMScriptThread
                  object allows easy management of the thread and flexibility
                  enough for quite complex tasks.In short: Use this object to run scripts (or call
                  routines implemented in them) asynchronously, if your
                  application needs to run scripts in separate threads and also
                  needs compatibility with Windows CE.
 Need of threadAt the first thought you may wonder why threads would be needed
              in scripting applications - such as ASP pages for example. By
              default ASP pages are programming environment based on
              request-response. Therefore the usual life cycle of a page is very
              limited - no more than a few seconds. This makes it harder to
              implement time consuming tasks directly in ASP. If, for instance,
              an user requests a data mining operation that needs minutes or
              even hours it is not possible to complete the operation and return
              response to the user in reasonable time. The server timeout will
              not help as no one will be eager to wait so long for response not
              knowing if the operation proceeds successfully and even if it is
              acceptable any network breakdown even for a second will waste all
              the results of the work. In Active Local Pages this issue is even
              bigger - running on a desktop the ASP applications are often
              expected to do some tasks typical for the desktop programs or the
              developer may want just to implement something in script instead
              of using/buying more advanced programming tool (such as C++,VB,
              Delphi etc.). In the most cases the critical part of the work is
              done by utility COM components - such as ADO, file access objects,
              filtering objects etc. This means that the efforts to build this
              part of the application with another (often expensive and also
              requiring new skills) tool will not pay back. So, implementing the
              asynchronous tasks in script if possible is very often the best
              balanced solution. Without the threading objects in this library
              the developer may use Windows Scripting Host to run a script in a
              separate process and get the results, for example, by reading a
              file generated by the script. There are also other techniques but
              actual improvement will be a component allowing the application to
              run a script asynchronously in a separate thread and check the
              results from time to time. If it is possible to control the thread
              - e.g. start/stop it, present data/messages to the script running
              in it (to achieve some dynamic synchronization) - then it will be
              even better. The thread classes in ActiveX pack1 library provide such
              features and an ASP application is able to overcome the
              limitations of the request-response architecture. In theory the
              simplicity of the request/response structure combined with the
              ability to perform background tasks and monitor them makes such a
              typical WEB development environment almost as powerful as any
              desktop programming environment, but still keeps the traits of a
              WEB development environment.  Later in this chapter you can see a simple sample on how
              the threads are used, but still a few words about real life usage
              will give you better view. Soon after implementing the first
              version of the COMThread object in our library we have been
              involved in two projects where it fitted. One of them was data
              mining - it required a lot of data to be extracted and organized
              from a data base designed for tasks very different from what we
              had to do with it. So, it required a lot of time, creation of
              temporary tables and so on. Over the full data base it took more
              than 15 minutes! There was no requirement what kind of application
              will do it - desktop or WEB. With ALP and a thread to perform the
              slow task we implemented it as WEB application for the desktop.
              After some time the client decided that the application can be
              installed on the WEB server as well and it needed only a few lines
              adjustments. In general the application collected the user
              preferences, set of complex rules and then it started the
              background operation. In the same time the user was able to check
              the progress, extract intermediate reports and even influence the
              process. The other task was much simpler - collecting data from
              the file system. In this case the thread collected/refreshed the
              data in a data base and the user was able to use the front end UI
              while the background data collection was in progress.    Using threads - exampleFor simplicity we will use the COMScriptThread object here. Let
              use something simple to illustrate it - for example finding the
              count of the prime numbers up to a certain number. We will use a
              slow script that does this in the worst possible way ;) - for the
              example purposes we need a slow operation. So, we will have two scripts - a
              controller script (we will use ASP page) and a script that will
              run in the thread. We can also implement this with the Micro
              Script Host where the place of the ASP controller page will be
              taken by a controller plain script. Let's start with the thread's
              script - that finds the count of the prime numbers:
               
              We will expect the max number to be specified in the
              Context("Max") and we will use Context("Current")
              to store the current number we check and also we will increment
              the Context("PrimeCount") each time we find a new prime
              number:
               Function CheckNum(n)
  Dim J
  For J = 2 To n - 1
    If (n Mod J) = 0 Then
      CheckNum = False
      Exit Function
    End If
  Next
  CheckNum = True
End Function
Dim I
Context("PrimeCount") = 0
For I = 2 To Context("MaxNum")
  Context("Current") = I
  If CheckNum(I) Then
    Context("PrimeCount") = Context("PrimeCount") + 1
  End If
NextThe script we have is simple. Remember that the Context collection
              is also available through the Value property of the
              COMScriptThread object. So the application that created the thread
              can check at any time how far the thread has gone. Let us now write a simple ASP page that starts this thread. We
              will omit any formatting and additional processing here: 
                Set Application("Thread") = Server.CreateObject("newObjects.utilctls.COMScriptThread")
' Copy this to local variable so we can write shorter statements
Set T = Application("Thread")
' Now we need to get the script source. Let us assume it is in the file thread.vbs
Set sf = Server.CreateObject("newObjects.utilctls.SFMain")
Set file = sf.OpenFile(Server.MapPath("thread.vbs")
If T.Start("VBScript",file.ReadText(-2)) Then
  ' Start is successful
Else
  ' Error occured (for example compile time error)
  Response.Write("Error: " & T.LastError)
End IfNow in another page (or in the same page if it is designed to
                be requested with some parameters that allow us to determine
                which action to perform) we can check the thread state. For
                example we can use code like this: If Application("Thread").Busy Then
  ' Let us display the results so far
  Response.write("Current number=" & Application("Thread")("Current") & "<BR>")
  Response.write("Prime numbers found=" & Application("Thread")("PrimeCount") & "<BR>")
Else
  If Application("Thread").Success Then
    ' Thread has finished its work we can display the results
    Response.write("Total Prime numbers found=" & Application("Thread")("PrimeCount") & "<BR>")
  Else
    ' Error - a run time error
    Response.Write("Error: " & T.LastError)
  End IF
End If If you have only one thread the above code is almost everything
              you need. May be a little more error checking will be needed
              depending on the complexity of the work done, but in general this
              is the important steps you need to do. After completing everything
              you can call Application("Thread").Stop and reuse
              the object again - start another script in it etc. But consider more complex application with many COMScriptObject-s,
              with many pages that may want to start/stop threads etc. In such
              case you may need to keep additional information with the threads,
              you may need even to synchronize the work with them etc. This
              applies to COMScriptObject and COMThread objects as well - in both
              cases you may want to construct something more complex. So, let us
              see what we will need: 
                Synchronizing the access to the thread. 
                Sometimes the application may be written in such a manner that
                concurrent requests to different pages may lead to usage of the
                same thread object. It is quite possible that two or more pages
                may want to use the thread for different purposes - for instance
                run different scripts. The very first thing you will need to
                deal with this is locking the thread object for certain task.
                Using the Application.Lock is one of the possible ways to
                go, but it locks the entire application and you may have several
                thread objects and no need to block all the other work, but only
                lock one thread object. You can use one CustomLock
                object kept in the Application under name derived from the
                thread's name - for example if you keep the thread in
                Application("Thread") you can keep the CustomLock for
                it in the Application("ThreadLock"). Then any page
                that wants to use this thread object may call
                Application("ThreadLock").Lock in order to be sure
                that it is the only one that works with it at this moment. So
                you can lock the object while you are loading/constructing the
                script source and call the start method. After that you should
                release the lock (Unlock the CustomLock object) and if there are
                other pages waiting for it they will be able to see that it is
                in use (see Busy and Active properties) and they may try to use
                another thread object (if you have many) or tell the user that
                the operation cannot be scheduled at this moment. Using several thread objects for different purposes.
                Aside of synchronization discussed above you may need to know
                what each thread does. If the tasks you run in them are too
                different (different scripts for example) you may need to attach
                some kind of labels - you can use again Application variables or
                use a Context collection value (for example you can name it
                TaskName) to save key names for the tasks. Thread pooling. In complex application where many
                threads are needed and different tasks are done in them
                implementing a thread pool will be the best way to go. How to do
                this? One simple technique is to keep an array of fixed size in
                the Application with one thread object in each element. Then you
                can keep another array in another Application variable where you
                store indicator values in each element (e.g. free/in use flag).
                Then you can implement a function in your ASP page (most likely
                in an include file) that finds the first free thread and signs
                it as used after returning it. Then you can keep the index of
                the thread used in a Session variable and each time a page needs
                to work with the thread you can refer to the thread used by
                index. So each task can be referred quite easily - by just using
                something like Application("Threads")(Session("MyThread"))
                and you will be sure that you will never start too many
                threads as their number is fixed when the array has been
                created. We want to remind you again that in ASP application you should
              take care to limit the number of threads started. So, if you
              expect too many of them to be needed better implement some kind of
              pooling in order to control the number and their use. The actual
              limitation should be decided over the machine resources. Another
              concern are the resources the thread are using - for example if
              they all use the same files/database, running too much threads may
              cause even negative results as they all will race for the same
              resources. Sometimes supporting two or more pools - each one used
              for the threads working with different set of resources may
              be  more effective than one pool.
         |