An Overview of Basic Threading Concepts

I l @ ve RuBoard

Visual Basic .NET and the .NET Framework provide a full set of threading capabilities that make creating and running simple threads very easy to do. But before we get into doing just that, let's take a step back and review how processes and threads are related and how this relationship can affect your application designs.

Processes and Threads

Applications run in separate processes on a computer. For each new application launched, a new process is created. A process by definition contains at least one execution thread and has its own address space. This serves to isolate applications from each other because processes cannot share memory directly. Isolation prevents one process from trampling over the memory of another process, ensuring, at least in theory, that one application cannot cause another to crash. This also means that applications cannot directly share memory-resident resources (arrays, classes, or variables ). Even sharing non-memory-resident resources, such as disk-resident files, can be tricky.

More Info

For ways to share resources across applications, see the discussion of remoting in Chapter 5.


Threads, on the other hand, are the basic unit to which an operating system allocates processor time. The operating system allocates execution time to threads, not (as you might think) processes. A thread requires an owner process and cannot exist on its own. Processes, on the other hand, can contain multiple threads but must contain at least one thread ”the main process thread (usually Sub Main ). When the main process thread exits, the entire process is terminated ”any other active threads will be prematurely terminated . Threads can share memory with other threads that are within the same process. A thread also has an associated set of resources that includes its own exception handlers, scheduling priority, and a set of structures that allow the operating system to preserve the thread's context as other threads are given execution time.

The .NET Framework takes this model a step further by introducing the concept of application domains . An application domain is a lightweight, managed subprocess that can contain one or more threads. Threads within application domains can create additional application domains.

Execution Time

Threads are granted execution time by the operating system in what are known as time slices . The duration of a time slice is system-dependent and varies between operating systems and processors. In the vast majority of environments, only one thread can be given execution control at a time. The exception is when threads are running on a multiprocessor machine.

Limitations of Threads

Any given system will have an upper limit on the number of threads per process. On systems running Microsoft Windows XP, that limit is approximately 2000 threads per process. As a practical matter, the limit is actually much lower. Each thread constitutes real physical resources on a machine. The memory requirements of preserving the thread context information cause the number of possible threads to be bounded by the available memory.

The memory commitment aside, tracking larger numbers of threads creates a significant burden for the operating system, which has to switch between all of the active threads on the system on a regular basis. If there are too many threads, the amount of execution time provided to each thread will not be enough to make significant progress in a reasonable amount of time. This will also affect other applications in the system. Remember that the processor execution time is divided among the active threads. If one application has a single thread and another has three, the first application will get only a quarter of the processing time. As the number of threads in the second application increases , the first application will get increasingly less processor time. This should highlight the need to be a good threading citizen. You can adversely affect other applications on the same machine if you use your threads unwisely.

The bottom line here is that you should create only as many threads as you need and no more. Due to the burden that additional threads impose on the system, you should make careful choices about what tasks belong in separate threads. Here are a couple of additional facts about threads:

  • The amount of time given to a thread is not guaranteed .

  • The order of thread activation is not guaranteed.

  • Events or operations occurring on different threads cannot be assumed to be synchronized; you must perform any synchronization explicitly.

Creating Threads

The core functionality of threading for Visual Basic .NET is contained in the System.Threading.Thread class. This class provides all of the operations that can be performed on managed threads. In the managed world, threads are encapsulated by the Thread class. You use the Thread class to create and manage additional threads within your application. Managed threads, like all other managed objects, are maintained by the .NET runtime environment.

There are three important steps to creating any managed thread in Visual Basic .NET:

  1. Create a method to serve as the thread's starting point.

  2. Create a ThreadStart delegate, using the AddressOf operator with the method you want called when the new thread starts.

  3. Create a Thread object and pass it the ThreadStart delegate you created.

After following these steps, you'll have a thread that can be started and run on its own. The following example demonstrates how to create two separate threads and start them. The example is among the chapter's sample files and is named Basic Threading.

 ImportsSystem.Threading ModuleBasicThreading PublicConstMAX_COUNTAsInteger=200 SubMain() 'Createthethreadobjects DimThread1AsNewThread(NewThreadStart(AddressOfThreadMethod1)) 'WecanomittheNewThreadStartandjustusetheAddressOfoperator. DimThread2AsNewThread(AddressOfThreadMethod2) 'Startthethreads Thread1.Start() Thread2.Start() 'Givetheuserachancetoreadtheinput Console.ReadLine() EndSub 'Therespectivethreadmethods PublicSubThreadMethod1() DimiAsInteger Fori=0ToMAX_COUNT Console.WriteLine("ThreadMethod1{0}",i) Next EndSub PublicSubThreadMethod2() DimiAsInteger Fori=0ToMAX_COUNT Console.WriteLine("ThreadMethod2{0}",i) Next EndSub EndModule 

When we run this application, the output looks like that shown in Figure  3-1. Both threads print out a repeated set of lines to the console. Note that your results (which thread will actually run first and which will finish first) might vary from run to run and will definitely vary from machine to machine. (Remember the three threading facts mentioned earlier.)

Figure 3-1. Sample output of the Basic Threading sample.

graphics/f03pn01.jpg

The Basic Threading sample demonstrates the simplest form of threading: the thread class is given the address of a method that it will execute. The method itself has no notion of threads, nor can we pass any parameters to the thread method. One solution to this, given the simplest case, is to declare global variables that are used by your thread methods. This is not very elegant and can be very messy. This does not necessarily present a problem for simple tasks, but it becomes an issue when more threads are involved or if you want to expose that functionality as a library to other developers.

The sample uses a global constant, MAX_COUNT , to pass information to the threads. The problem with this is that the mechanism is imprecise ”both of the thread methods use the same constant. But what if we want the threads to execute differently? What if we need to have each thread execute with different initial conditions and we want to create an arbitrary number of threads? Obviously, it gets much trickier using dedicated global variables ”we have to create specific variables for each thread, which can lead to a maintenance nightmare.

What we need is a way to pass information to the thread execution methods without creating specific global variables for each thread. What we need is a better way to manage thread creation and execution: encapsulation .

I l @ ve RuBoard


Designing Enterprise Applications with Microsoft Visual Basic .NET
Designing Enterprise Applications with Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 073561721X
EAN: 2147483647
Year: 2002
Pages: 103

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net