Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
programming4us
Windows 7

Visual Basic 2010 : Understanding the .NET Thread Pool & Threads Synchronization

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
6/26/2011 4:23:07 PM

Understanding the .NET Thread Pool

When you have one or two threads, things are also easy for performance. But if you decide to split a process or an application across lots of concurrent threads, the previous approach can cause performance and resources overhead. So you should manually search for the best configuration to fine-tune system resources consumption with your threads. Your application can run on different configurations in terms of available memory, processors, and general resources, so it is difficult to predict how many threads you can launch concurrently on target machines without affecting performance and causing overhead. Fortunately the .NET Framework maintains its own set of threads that you can also reuse for your purposes instead of writing code for creating and running new threads, ensuring that only the specified number of threads will be executed concurrently, all controlled by the Framework. The set is named thread pool and you access it via the System.Threading.ThreadPool class. This class offers static methods for assigning tasks to threads in the box; because the thread pool has a predefined number of available threads If they are all busy doing something else, the new task is put into a queue and is executed when a thread completes its work. To take advantage of threads in the thread pool, you invoke the System.Threading.ThreadPool.QueueUserWorkItem method, as demonstrated in the following code:

Sub QueueWork()

ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf FirstWorkItem))
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf SecondWorkItem))
ThreadPool.QueueUserWorkItem(New WaitCallback(Sub()
Console.
WriteLine _
("Third work item")
End Sub))
End Sub

Private Sub FirstWorkItem(ByVal state As Object)
Console.WriteLine("First work item")
End Sub
Private Sub SecondWorkItem(ByVal state As Object)
Console.WriteLine("Second work item")
End Sub


With QueueUserWorkItem you basically ask the runtime to put the specified task in the execution queue so that it will be executed when a thread in the thread pool is available. The WaitCallBack delegate simply allows passing state information and requires referred methods to have an argument of type Object in their signatures. Notice how you can still use lambdas to supply the desired action.

Getting and Setting Information in the Thread Pool

You can query information on the thread pool by invoking the ThreadPool.GetMaxThreads, ThreadPool.GetMinThreads, and ThreadPool.GetAvailableThreadsGetMaxThreads return the maximum number of concurrent threads that are held by the thread pool; GetMinThreads return the number of idle threads that are maintained waiting for the first new task being requested, whereas GetAvailableThreads return the number of available threads. Whichever you use, they all return two values: the number of worker threads and of completion threads. Worker threads are units of execution, whereas completion threads are asynchronous I/O operations. The following code demonstrates how you get information on available threads: methods.

Sub PoolInfo()
Dim workerThreads As Integer
Dim completionPortThreads As Integer

ThreadPool.GetAvailableThreads(workerThreads,
completionPortThreads)
Console.WriteLine("Available threads: {0}, async I/O: {1}",
workerThreads, completionPortThreads)
Console.ReadLine()
End Sub

workerThreads and completionPortThreads arguments are passed by reference; this is the reason why you need variables for storing values. Similarly you can use SetMaxThreads and SetMinThreads to establish the maximum number of requests held by the thread pool and the minimum number of idle threads. The following line is an example:

ThreadPool.SetMaxThreads(2000, 1500)

Threads Synchronization

Until now you saw how to create and rung new threads of execution to split big operations across multiple threads. This is useful but there is a problem: Imagine you have multiple threads accessing the same data source simultaneously; what happens to the data source and how are threads handled to avoid errors? This is a problem that is solved with the so-called thread synchronization. Basically the idea is that when a thread accesses a resource, this resource is locked until required operations are completed to prevent other threads from accessing that resource. Both Visual Basic and the .NET Framework respectively provide keywords and objects to accomplish threads synchronization, as covered in the next subsections.

The SyncLock..End SyncLock Statement

The Visual Basic language offers the SyncLock..End SyncLock statement that is the place where you can grant access to the specified resource to only one thread per time. For example, imagine you have a class where you define a list of customers and a method for adding a new customer to the list, as demonstrated by the following code snippet:

Private customers As New List(Of String)


Sub AddCustomer(ByVal customerName As String)

SyncLock Me
customers.Add(customerName)
End SyncLock
End Sub

Basically the preceding code locks the entire enclosing class, preventing other threads from accessing the instance until the requested operation completes. By the way, locking an entire class is not always the best idea, because it can be expensive in terms of resources and performances, and other threads cannot also access other members. Unfortunately you cannot directly lock the resource; the MSDN documentation in fact states that you need to declare a lock object that you can use as follows:

Private customers As New List(Of String)
Private lockObject As New Object()

Sub AddCustomer(ByVal customerName As String)

SyncLock lockObject
customers.Add(customerName)
End SyncLock
End Sub

The lock object is typically a System.Object. Using an object like this can ensure that the code block executed within SyncLock..End SyncLock will not be accessible by other threads. Another approach is using GetType instead of the lock object, pointing to the current type where the synchronization lock is defined. The following code demonstrates this:

Class Customers
Inherits List(Of String)

Public Sub AddCustomer(ByVal customerName As String)
SyncLock GetType(Customers)
Me.Add(customerName)
End SyncLock
End Sub
End Class

The SyncLock..End SyncLock statement is typical of Visual Basic language grammar. By the way, the statement is translated behind the scenes into invocations to the System.Threading.Monitor class as is described in next section.

Synchronization with the Monitor Class

The System.Threading.Monitor class is the support object for the SyncLock..End SyncLock statement, and the compiler translates SyncLock blocks into invocations to the Monitor class. You use it as follows:

Sub AddCustomer(ByVal customerName As String)
Dim result As Boolean

Try
Monitor.Enter(lockObject, result)
customers.Add(customerName)
Catch ex As Exception
Finally
Monitor.Exit(lockObject)
End Try
End Sub

Tip

Monitor.Enter now has an overload that takes a second argument of type Boolean, passed by reference, indicating if the lock was taken. This is new in .NET Framework 4.0.


Basically Monitor.Enter locks the object whereas Monitor.Exit unlocks it. It is fundamental to place Monitor.Exit in the Finally part of the Try..Catch block so that resources will be unlocked anyway. At this point you might wonder why use Monitor instead of SyncLock..End SyncLock because they produce the same result. The difference is that Monitor also exposes additional members, such as the TryEnter method that supports timeout, as demonstrated here:

Monitor.TryEnter(lockObject, 3000, result)

This code attempts to obtain the lock on the specified object for three seconds before terminating.

Read/Write Locks

A frequent scenario is when you have a shared resource that multiple reader threads need to access. In a scenario like this, you probably want to grant writing permissions just to a single thread to avoid concurrency problems. The .NET Framework provides the System.Threading.ReaderWriterLockSlim class, which provides a lock enabled for multiple threads reading and exclusive access for writing.

ReaderWriterLock Class

The .NET Framework still provides the ReaderWriterLock class, as in its previous versions, but it is complex and used to handle particular multithreading scenarios. Instead, as its name implies, the ReaderWriterLockSlim class is a light-weight object for reading and writing locks.


Generally an instance of this class is declared as a shared field and is used to invoke both methods for reading and writing. The following code demonstrates how you enable a writer lock:

Private Shared rw As New ReaderWriterLockSlim


Sub AddCustomer(ByVal customerName As String)
Try

rw.EnterWriteLock()
customers.Add(customerName)
Catch ex As Exception
Finally
rw.ExitWriteLock()
End TrThe
End Sub

This ensures that only one thread can write to the customers’ collection. The next code snippet shows instead how you can enable a reader lock:

Sub GetInformation()
Try
rw.EnterReadLock()
Console.WriteLine(customers.Count.ToString)
Catch ex As Exception
Finally
rw.ExitReadLock()
End Try
End Sub

ReaderWriterLockSlim is an object you should use if you expect more readers than writers; in other cases you should consider custom synchronization locks implementations.

Other -----------------
- Visual Basic 2010 : Processes and Multithreading
- Visual Basic 2010 : Implementing Query Interceptors
- Microsoft Visio 2010 : Adding Sophistication to Your Drawings - Adding ScreenTips and Comments
- Microsoft Visio 2010 : Adding Sophistication to Your Drawings - Positioning Shape Text
- Monitoring and Maintaining Windows 7 : Using Event Viewer
- Monitoring and Maintaining Windows 7 : Setting Up Task Scheduler
- Visual Basic 2010 : Implementing and Consuming WCF Data Services - Implementing Service Operations
- Visual Basic 2010 : Consuming WCF Data Services
- Visual Basic 2010 : Implementing WCF Data Services
- Microsoft Visio 2010 : Adding Sophistication to Your Drawings - Orienting Shape Text
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server