By: Jeremy Holley
Multithreading is one of the more advanced ways of speeding up your applications. Most every developer will have to write a concurrent application sooner or later. In this part I will cover the basic techniques for multithreading in .net such as signaling and accessing shared resources. What is .net? Read more about it here.
Threading poses us with unique issues regarding the access of shared resources (e.g. variables, lists, etc.). You can have multiple threads trying to modify the same resource which can lead to unpredictable results.
To prevent threads from accessing the same resource at the same time we can use constructions such as the semaphores or monitors. In C# the monitor implementation is the lock statement. To implement it you need to create a locker object which has to be locked before the shared resourced is accessed and then unlocked afterwards. Once the lock object is locked other threads have to wait until the object is unlocked. Exampled Below
The bool in the above example isDone is a shared resource between threads. The example above has 2 threads the main thread and then the one that is invoked from the main thread. Both will try to access IsDone. Looking at method proc execution we can see that isDone is accessed twice. Once to check its value and once to set its value if it was false. The issue here is the main thread may access isDone first while its value is false then give up processing time to thread 2 which will also see isDone as false and the console will respond with “done” twice. That is behavior we do not want. The solution for this issue is to use a lock object.
Now the if statement is secured by a lock which forces every thread that wants to enter it to obtain the lock. Once a lock is obtained by a thread another thread can not proceed. It will wait until the lock is freed. Above, when the main thread has the lock it will execute the if statement before handing processing back to the second thread.
The Following Code snippets have equivalent behavior:
Another technique to use is signaling. Signaling is notifying other threads. One example is a thread can invoke another thread then wait for the invoked thread to signal completion. Thread 2 would be performing some operation while thread 1 waits. One thread 2 completes its task it sends a signal back to thread 1 which then continues on.
Below the main thread creates a new thread to perform thread2Operation. After that it performs an operation then waits for thread 2 to signal that it is finished. Once that signal is received thread 1 proceeds.
The basic implementation of multithreading in an application is the Producer-Consumer which is widely used in many real-life applications. Below is an example:
Multithreading in .NET offers many advantages such as faster applications or a responsive UI. It does however make it more difficult to debug and can introduce additional issues. The advantages do not always outweigh the additional complexity that it introduces. However, being familiar with what it can and cannot do is part of becoming a master developer.
Threading in C# by Joseph Albahari (http://www.albahari.com/threading/)
Threading in .NET by Jon Skeet (http://jonskeet.uk/csharp/threads/)
Author: Jeremy Holley
At a recent client, I was tasked with creating an Azure Queue Service bus. Setting up the queue itself is very easy using the Azure dashboard. Getting messages out of the queue is a bit more complicated. I decided to use the Worker Role for Azure Service Bus to accomplish the handling of messages. The advantage of using worker roles is the load leveling they provide and scalability with their ease of spinning up more instances of the worker in Azure.
Azure Worker Role
The Worker role provides the mid-tier business logic for a multi-tier queue service. It pops messages off of the Queue and handles the message based on type via a handler factory.
Set up the development environment
Before we can begin to develop the Worker Role we need to set up Visual Studio properly.
- Connect Visual Studio to an Azure account.
- You may need the Azure SDK installed for you to see the proper projects.
- In Visual Studio, create a new Project.
- Select Azure Cloud Service. In this example I am going to name mine ‘WorkerRoleExample’.
- In the next dialog select ‘Worker Role.’
Doing this we will be given a Solution with two projects
We will need to add two more projects to define messages and message handlers. You don’t necessarily need to have them in separate projects but I like to organize my Worker solutions in this manner.
The first project we will Name ExampleRole.Contracts and it will be a Class Library.
The Second Project we will name ExampleRole.Processors and it will also be a class library.
Once those are completed our Solution should look something like this.
We will now start coding the worker. Starting in the ExampleRole.Contracts Project
Example Role Contracts
Before we can start coding we need to make sure that we have a reference to JSON. We need to add the Newtonsoft NuGet package for it.
First, we will add a EventTypes enumeration. Here we will define some basic event types. First, we will have an announce message that we will use to announce that the queue worker is alive. This will be for internal logging/tracing and to show that a message has been handled on start up. The other initial type we will call NoEvent that one we will use for test handling messages. The enumeration should look like this initially.
Beyond these two message types we could define actual messages that we need to handle from the queue. What I like to do is to number my real messages starting at 100 and counting by 100’s from there to give room for message details. For example, if we have to do a create, update and delete processes on an Order object we could have something along the lines of the below example.
Next, we will define the base message format. We will add a new class MessageHeaderBase
Here we defined the header properties for the message. For the header items, we will use three properties.
Version number so that if the message changes we can handle older messages based on version number. This is not strictly required but it is a way to handle changes to the worker when you may have queue clients sending messages that are slightly different.
EventType refers to the enumeration EventTypes and tells the worker what handler to send the message to.
EventName is a friendly name for the event that can be used in logging to help humans see what sort of messages are being passed. This field is not absolutely necessary and is more of field to help troubleshooting.
Lastly, the message base will be created in a new class MessageBase. Here the class will inherit MessageHeaderBase and will have the EventData field which will carry the payload of the message and can be various types of data so we will use a generic type for it.
With that the class should look something like this.
Now we will move on to adding a class to handle the serialization of messages into and out of JSON.
In the From method we intake a generic model and serialize the object into JSON.
Then in the ToModel we take serialized JSON and try to convert it into one of our defined message contracts.
The class should end up looking something like this.
Finally, we will add a folder to hold our messages and then define our two basic messages.
We will define the AnnounceMessage Class. In this class we will have a faily simple string that just passes a string announce message to its handler. It should end up looking like this.
We have the event type set to announce and our friendly name is the same. Finally, its data is the string that is past in when the message is created.
Now we will define a test message that we can use to send just basic test data into the queue. This message contract is similar to the announce message but instead of passing a simple string we will pass a sub object that contains a Name property that is a string and a number property. This will show that complex object can be past as payloads.
We are done with the contracts project. Now we will move onto the ExampleRole.Processors project.
Example Role Processors
To start we need to add a reference to the ExampleRoles.Contracts project
We will start coding by creating an Interface for the message handlers called IMessageHandler.
The interface is very simple with a single method Handle. All it does is allows the factory to push out instances of the various handlers.
Now we will add handlers for our two message contracts.
We need to add the AnnounceHandler. This is a simple message so all we need to do is to take the message’s data and push it to the trace listener because it is used to see if the worker is alive.
For test messages, we will create a TestHandler. In this example, we will just push the message information to the trace log but here you could handle the message in various other ways. You could push the data to a SQL database or onto some other end point.
Now that we have handlers for our message contracts we can define handler factory. We will add a new class called MessageProcessor.
When instantiating the class we will need to add the handlers to a dictionary that defined what messages can be handled. Our starting code will look like this:
From there we will need to define the AddHandler method. In that method, we will add the handlers to the dictionary.
Finally, we will need to add another method to get the processors called GetProcessor.
Once we are done with that we are done with the Processor project.
Example Role Project
TO get started we will need a reference to both the Contracts and Processors projects to be added.
We will start coding in the WorkerRole.cs file.
There we will find a lot of code already in place for us but we are missing a class level variable for the QueueClient which is in the Microsoft.ServiceBus.Messaging name space. This might be missing from the project so we will need to add a reference to it using NuGet.
We are looking for the WindowsAzure.ServiceBus package
Once that is installed we can add the QueueClient to the code and the queue name also. Once added the code will look something like this. All that needs to be changed is the QueueName constant needs to be changed to the name of your queue in Azure.
Now we move onto the Run Method WorkerRole.cs. Here will do the basic tasks of the message pump.
In the run method, we setup the message options. We want the messages to autocomplete to callback the complete call once the message processing has concluded. We only on 1 concurrent callback per pump right now and finally if we get an exception we want to send that exception to the LogErrors Method.
Next, we want to initiate the client’s OnMessage routine. Here we receive a message from the Queue and get the text of the message body. We then send that body payload to the ProcessMessage method. If an exception occurs, we catch it and log it. Finally, we tell the pump to wait one tick before checking for another message on the queue.
Now we will define the ProcessMessage method.
In the process message method, we do a basic handler factory where we find the type of message we are dealing with and instantiate the appropriate handler to handle the message’s payload. First it gets message header to find the type of message that it is dealing with. From there is gets the handler for the message type then has the handler process the message
Now we will define the LogError method to log any errors we will encounter.
In this example we will just push the errors to the trace log but in a production worker you could push the errors to a database or other logging solution.
Now we will move onto the OnStart method. This method handles the startup of the worker. If creates the queue client and sends the initial announce message(s).
Finally, we will handle the OnStop method. This method takes care of the cleanup of objects that need to be explicitly cleaned up.
With that we are done coding the worker. This example just starts a worker against a queue that needs to be defined by both the name in the WorkerRole.cs code and in the App.config in the app settings.
With the proper connection string and queue name this code should be able to handle the two message types we have defined.
Worker Roles for Azures are a useful tool in any scalable multi-tier solution. They allow you to decouple your UI applications from direct service calls through asynchronous calls to a queue. This enables the components of the application to be disconnected and allows you to update pieces without losing functionality. If the worker is taken off line for updates or in case of failure the messages are still stored on the queue until the worker is available again. Another scenario would be for the consuming worker to only come online at certain times of the day allowing offloading of processing to nonpeak times.
Software Technology Group’s certifications include Azure Fundamentals. To learn more about how we can help you with your .NET development needs, contact us. We’d love to hear from you.
Author: Jeremy Holley