Saturday, July 26, 2008

Advantages and Disadvantages of Thread pool

Benefits of Using the Thread Pool

Using the thread pool is the easiest technique you can use to create a multithreaded application for the following reasons:

  • You do not have to create, manage, schedule, and terminate your thread, the thread pool class do all of this for you.

  • There is no worries about creating too many threads and hence affecting system performance. Thread pool size is constrained by the .NET runtime. The number of threads you can use at the same time is limited.

  • You need to write less code, because the .NET framework manages your thread internally with a set of well tested, and bug free routines.

Limitations of Using the Thread Pool

Despite the ease of use, the thread pool has the following limitations or disadvantages when compared to manually managing your threads:

  • With thread pool, you have no control over the state and priority of the thread.
  • With thread pool, you can not give a stable identity to your thread and keep tracking it.
  • When submitting a process to the thread pool, you have no idea when the process will be executed. Your process may be delayed when there are high demand on the thread pool.
  • The thread pool is not suitable when you want to run two tasks or processes using two threads, and need these two tasks to be processed simultaneously in a deterministic fashion.
  • The .NET framework uses the thread pool for asynchronous operations, and this places additional demand on the limited number of available threads.
  • Despite of robust application isolation, there are situations where your application code can be affected by another application code.
In situations where you can not use the thread pool because of its limitations, you can create new threads manually and manage them yourself. This technique is much more complex than using the thread pool, but it gives you more control over your threads.

Thread Pool

Instead of creating a thread each time we need one, and then destroying it after finishing, the .NET framework introduces the concept of thread pool. In the thread pool technique, and instead of creating a new thread whenever you need one, your application will obtain a thread from the thread pool. After that obtained thread completes its task, it will be returned to the thread pool instead of destroying it - waiting for the next acquiring. This reusability increases the overall application performance, and reduces the cost of excessive thread creation and termination.

To make use of this technique, you need to use the System.Threading.ThreadPool class. The thread pool will be created the first time you use it. The number of total threads in this pool is restricted by default to 25 threads. This means that all of these 25 threads may be busy at some point. If you need to acquire a new thread at this point, your task will be scheduled waiting for a thread to finish its task and return to the pool.

In the "default.aspx.vb" file, import the "system.Threading" name space as shown in the following line of code.

1
Imports System.Threading

Create a time consuming method that will be executed in background in a separate thread. To be able to assign this method to the thread pool, it must have the same signature as the "WaitCallBack" delegate. This delegate has the following declaration:


Public Delegate Sub WaitCallback(ByVal state As Object)

This delegate represents a callback method to be executed by a thread pool thread. The "state" parameter represents the information that will be used by your time consuming method if you need to pass information to it.

So, our time consuming method will be as indicated in the following code snippet:


17
Private Sub LongTimeTask(ByVal s As Object)
18
19 Dim i As Integer
20 Dim str As String
21 str = s.ToString
22
23 For i = 0 To 1000
24 str = str + "--" + str
25 Next
26
27 End Sub

Now, in the button click handler type the following lines of code:


5
Protected Sub Button1_Click(ByVal sender As _
6 Object, ByVal e As System.EventArgs) Handles Button1.Click
7
8 If ThreadPool.QueueUserWorkItem( _
9 New WaitCallback(AddressOf LongTimeTask), TextBox1.Text) _
10 Then
11 Label2.Text = "Queued successfully"
12 Else
13 Label2.Text = "Failed"
14 End If
15
16 End Sub

In the line #8 of the above code, we used the ThreadPool.QueueUserWorkItem function to queue our time consuming method for execution in a separate thread from the thread pool. The first parameter to this function is a new instance of the WaitCallBack delegate that represents the method to be executed. In our case, the method to be executed is the 'LongTimeTask' method. The second parameter is the parameter to be passed to the 'LongTimeTask' method itself. In our case this parameter is the text entered by the end user in the text box control. This function returns 'True' when the queuing operation succeed, or 'False' when it fails.

Now, run your application and enter any text into the text box, then click the button, and observe the results.

It will be much better to enter long text in the text box, or to increase the number of loop iterations to get better feeling of this operation. You can also add a new text box control to the "default.aspx" page, so you can test your user interface responsiveness while you run the time consuming task at background.

That's it ...

As you can see it is so easy to use this technique to solve your annoying time consuming tasks problem. Be warned then! This ease will cost you.

MultiThreading

Multithreading is a technique that can be used to perform time consuming tasks in a separate additional thread other than the main application thread.

When you, for example, have a time-consuming function, you may need to call this function as a response of a button click. Now, instead of freezing all your application waiting for this function to return / to finish, you can create a new thread and assign this function to. When you do this, your application interface will not be blocked and you can use it to perform other tasks. At the same time, your time-consuming task is being carried out in the background.

You can think of it as the two threads: the main one, and the newly created one. Both are running in parallel, and this improves the performance and responsiveness of your application.

Advantages and Disadvantages of Using Multithreading

Despite improving your application's performance, and avoiding unresponsive user interface, multithreading has the following disadvantages:

  • There is a runtime overhead associated with creating and destroying threads. When your application creates and destroys threads frequently, this overhead affects the overall application performance.
  • Having too many threads running at the same time decreases the performance of your entire system. This is because your system is attempting to give each thread a time slot to operate inside.
  • You should design your application well when you are going to use multithreading, or otherwise your application will be difficult to maintain and extend.
  • You should be careful when you implement a multithreading application, because threading bugs are difficult to debug and resolve.

Notes:

  • Each time a thread is created, a certain amount of memory is consumed to hold this thread context information. Hence, the number of threads that can be created is limited by the amount of available memory.

  • More threads does not mean a faster responsive application, instead it can decrease the performance of your application.

Sealed Classes

Classes can be declared as sealed. This is accomplished by putting the sealed keyword before the keyword class in the class definition. For example:

public sealed class classSealed
{
// Class members here.
public string ID;
public double Price;

}
In the following code listing the implementation of a sealed class has been tested.

classSealed sc=new classSealed();
sc.ID=”C1”;
sc.Price=500.00;
double Samt=sc. CalculatePrice();
Response.Write(“Total Net Price of Product : “ +” “+sc.ID +” “+is+” “+Samt);
Response.Write(“
”);


A sealed class cannot be used as a base class. For this reason, it cannot also be an abstract class. Sealed classes are primarily used to prevent derivation. Because they can never be used as a base class, some run-time optimizations can make calling sealed class members slightly faster. Sealing a class means one can not derive from it. Sealing a method means one can not override it. In C# structs are implicitly sealed; therefore, they cannot be inherited. If we try to inherit from a sealed class in another class we will get compile time error about Inconsistent accessibility (code is shown in following code listing).

public class TestClass : classSealed
{
}

In C# a method can not be declared as sealed. However when we override a method in a derived class, we can declare the overridden method as sealed as shown below. By declaring it as sealed, we can avoid further overriding of this method.

public class testClass
{
public int x;
public int y;
public virtual void testMethod(){

}

}

public class TestClass: testClass
{
public override sealed void testMethod()
{

}
}

Abstract Classes or Interfaces

An abstract class only allows other classes to inherit from it and cannot be instantiated. When we create an abstract class, it should have one or more completed methods but at least one or more uncompleted methods and these must be preceded by the key word abstract. If all the methods of an abstract class are uncompleted then it is the same as an interface, but there is a restriction that it cannot make a class inherit from it, which means it can not work as a base class.

An interface is defined by the key word interface. An interface has no implementation; it only has the definition of the methods without the body. When we create an interface, we are basically creating a set of methods without any implementation. A class implementing an interface must provide the implementation of the interface members. All the methods and properties defined in an interface are by default public and abstract

Abstract classes can add more functionality without destroying the child classes that were using the old version. Abstract classes provide a simple and easy way to version our components. By updating the base class, all inheriting classes are automatically updated with the change. In an interface, creation of additional functions will have an effect on its child classes due to the necessary implementation of interface Methods in classes. Abstract classes should be used primarily for objects that are closely related, whereas interfaces are best suited for providing common functionality to unrelated classes. Say there are two classes, bird and airplane, and both of them have methods called fly. It would be ridiculous for an airplane to inherit from the bird class just because it has the fly() method. Rather, the fly() method should be defined as an interface and both bird and airplane should implement that interface. If we want to provide common, implemented functionality among all implementations of component, we should use an abstract class. Abstract classes allow us to partially implement classes, whereas interfaces contain no implementation for any members. So the selection of interface or abstract classes depends on the needs and design of our project. We can make an abstract class, interface, or combination of both depending on our needs.

The most likely situation in which we make a class or method sealed will be if the class or method is internal to the operation of the library, class, or other classes that we are writing. Because any attempt to override some of its functionality will cause problems. We can mark a class or method as sealed for commercial reasons, in order to prevent a third party from extending our classes. For example, in the .NET base class library string is a sealed class.

We should not use the sealed key word on a method unless that method is itself an override of another method in some base class. If we are defining a new method and we don’t want anyone else to override it, we should not declare it as virtual in the first place. If however, we have overridden a base class method, the sealed keyword provides a way of ensuring that the override supplied to a method is a “final” override that means no one else can override it again.

As given in MSDN

Here are some recommendations to help you to decide whether to use an interface or an abstract class to provide polymorphism for your components.

  • If you anticipate creating multiple versions of your component, create an abstract class. Abstract classes provide a simple and easy way to version your components. By updating the base class, all inheriting classes are automatically updated with the change. Interfaces, on the other hand, cannot be changed once created. If a new version of an interface is required, you must create a whole new interface.
  • If the functionality you are creating will be useful across a wide range of disparate objects, use an interface. Abstract classes should be used primarily for objects that are closely related, whereas interfaces are best suited for providing common functionality to unrelated classes.
  • If you are designing small, concise bits of functionality, use interfaces. If you are designing large functional units, use an abstract class.
  • If you want to provide common, implemented functionality among all implementations of your component, use an abstract class. Abstract classes allow you to partially implement your class, whereas interfaces contain no implementation for any members.



Suppress Finalization

After the Dispose method has been called on an object, you should suppress calls to the Finalize method by invoking the GC.SuppressFinalize method as a measure of performance optimization. Note that you should never change the order of calls in the finalization context (first Dispose(true) and then GC.SupressFinalize) to ensure that the latter gets called if and only if the Dispose method has completed its operation successfully.

The following code illustrates how to implement both the Dispose and Finalize pattern for a class.

   public class Base: IDisposable
{
private bool isDisposed = false;

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!isDisposed)
{
if (disposing)
{
// Code to dispose the managed resources
// held by the class
}
}
// Code to dispose the unmanaged resources
// held by the class
isDisposed = true;
base.Dispose(disposing);
}
~Base()
{
Dispose (false);
}
}
You should not reimplement IDisposable for a class that inherits from a base class in which IDispose has already been implemented. The following code snippet may help you understand this concept:

   public class Base: IDisposable
{
private bool isDisposed = false;

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!isDisposed)
{
if (disposing)
{
// Code to dispose managed resources
// held by the class
}
}
// Code to dispose unmanaged resources
// held by the class
isDisposed = true;
base.Dispose(disposing);
}
~Base()
{
Dispose (false);
}
}

public class Derived: Base
{
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Code to cleanup managed resources held by the class.
}

// Code to cleanup unmanaged resources held by the class.

base.Dispose(disposing);
}
// Note that the derived class does not // re-implement IDisposable
}
In the preceding code, what if the Dispose method were to throw an exception? In that case, the Finalize method would exit prematurely, and the memory would never be reclaimed. Hence, in such situations, it is advisable to wrap the Dispose method in a try-catch block. This will prevent finalization exceptions from orphaning the object.

Note the following points when implementing disposable types:

  • Implement IDisposable on every type that has a finalizer
  • Ensure that an object is made unusable after making a call to the Dispose method. In other words, avoid using an object after the Dispose method has been called on it.
  • Call Dispose on all IDisposable types once you are done with them
  • Allow Dispose to be called multiple times without raising errors.
  • Suppress later calls to the finalizer from within the Dispose method using the GC.SuppressFinalize method
  • Avoid creating disposable value types
  • Avoid throwing exceptions from within Dispose methods
In a managed environment, the GC takes care of freeing unused objects. In contrast, in unmanaged languages such as C, developers had to release unused objects explicitly that were created dynamically in the heap. However, a proper understanding of both the Dispose and Finalize methods goes a long way toward designing efficient applications.

The Dispose/Finalize Pattern

Microsoft recommends that you implement both Dispose and Finalize when working with unmanaged resources. The correct sequence then would be for a developer to call Dispose. The Finalize implementation would run and the resources would still be released when the object is garbage collected even if a developer neglected to call the Dispose method explicitly.

Dispose/Finalize pattern should be used only when your type invokes unmanaged code that
allocates unmanaged resources (including unmanaged memory) and returns a handle that you must use eventually to release the resource. Both dispose and finalize must chain up to their parent objects by calling their parent's respective methods after they have disposed or finalized
their own members".

Simply put, cleanup the unmanaged resources in the Finalize method and the managed ones in the Dispose method, when the Dispose/Finalize pattern has been used in your code.

As an example, consider a class that holds a database connection instance. A developer can call Dispose on an instance of this class to release the memory resource held by the database connection object. After it is freed, the Finalize method can be called when the class instance needs to be released from the memory. According to MSDN, "Finalize provides a backup to prevent resources from permanently leaking if the programmer fails to call Dispose"

How to use Dispose method

Unlike Finalize, developers should call Dispose explicitly to free unmanaged resources. In fact, you should call the Dispose method explicitly on any object that implements it to free any unmanaged resources for which the object may be holding references. The Dispose method generally doesn't free managed memory—typically, it's used for early reclamation of only the unmanaged resources to which a class is holding references. In other words, this method can release the unmanaged resources in a deterministic fashion.

However, Dispose doesn't remove the object itself from memory. The object will be removed when the garbage collector finds it convenient. It should be noted that the developer implementing the Dispose method must call GC.SuppressFinalize(this) to prevent the finalizer from running

Note that an object should implement IDisposable and the Dispose method not only when it must explicitly free unmanaged resources, but also when it instantiates managed classes which in turn use such unmanaged resources. Implementing IDisposable is a good choice when you want your code, not the GC, to decide when to clean up resources. Further, note that the Dispose method should not be called concurrently from two or more different threads as it might lead to unpredictable results if other threads still have access to unmanaged resources belonging to the instance.

The IDisposable interface consists of only one Dispose method with no arguments.

   public interface IDisposable
{
void Dispose();
}
The following code illustrates how to implement the Dispose method on a class that implements the IDisposable interface:

   class Test : IDisposable
{
private bool isDisposed = false;

~Test()
{
Dispose(false);
}

protected void Dispose(bool disposing)
{
if (disposing)
{
// Code to dispose the managed resources of the class
}
// Code to dispose the un-managed resources of the class

isDisposed = true;
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}



In the preceding code, when the Boolean variable disposed equals true, the object can free both managed and unmanaged resources; but if the value equals false, the call has been initiated from within the finalizer (~Test) in which case the object should release only the unmanaged resources that the instance has reference to.

Dispose & Finalize

Finalization is the process by which the GC allows objects to clean up any unmanaged resources that they're holding, before the actually destroying the instance. An implementation of the Finalize method is called a "finalizer." Finalizers should free only external resources held directly by the object itself. The GC attempts to call finalizers on objects when it finds that the object is no longer in use—when no other object is holding a valid reference to it. In other words, finalizers are methods that the GC calls on "seemingly dead objects" before it reclaims memory for that object.

The GC calls an object's finalizer automatically, typically once per instance—although that's not always the case. You should never rely on finalizers to clean up managed resources. A class that has no finalizer implemented but is holding references to unmanaged objects can cause memory leaks, because the resources might become orphaned if a class instance is destroyed before releasing the unmanaged objects.

The time and order of execution of finalizers cannot be predicted or pre-determined. This is why you'll hear that the nature of finalization is "non-deterministic." Further, due to the non-deterministic nature of finalization the framework does not and cannot guarantee that the Finalize method will ever be called on an instance. Hence, you cannot rely upon this method to free up any un-managed resources (such as a file handle or a database connection instance) that would otherwise not be garbage collected by the GC.

Note that you cannot call or override the Finalize method. It is generated implicitly if you have a destructor for the class.

class Test
{

// Some Code

~Test
{
//Necessary cleanup code
}
}

In the preceding code, the ~Test syntax declares an explicit destructor in C#, letting you write explicit cleanup code that will run during the finalize operation.

The framework implicitly translates the explicit destructor to create a call to Finalize:

   protected override void Finalize()
{
try
{
//Necessary cleanup code
}
finally
{
base.Finalize();
}
}


Note that the generated code above calls the base.Finalize method.

You should note the following points should when implementing finalizers:

  • Finalizers should always be protected, not public or private so that the method cannot be called from the application's code directly and at the same time, it can make a call to the base.Finalize method
  • Finalizers should release unmanaged resources only.
  • The framework does not guarantee that a finalizer will execute at all on any given instance.
  • Never allocate memory in finalizers or call virtual methods from finalizers.
  • Avoid synchronization and raising unhandled exceptions in the finalizers.
  • The execution order of finalizers is non-deterministic—in other words, you can't rely on another object still being available within your finalizer.
  • Do not define finalizers on value types.
  • Don't create empty destructors. In other words, you should never explicitly define a destructor unless your class needs to clean up unmanaged resources—and if you do define one, it should do some work. If, later, you no longer need to clean up unmanaged resources in the destructor, remove it altogether.
Finalize() is a non-explicit way to clean up resources. Because you can't control when (or even if) the GC calls Finalize, you should treat destructors only as a fallback mechanism for releasing unmanaged resources. Instead, the approved way to release unmanaged resources is to make your class inherit from the IDisposable interface and implement the Dispose() method