Click here to Skip to main content
15,885,216 members
Articles / Programming Languages / C#

Simple mutlithreaded application

Rate me:
Please Sign up or sign in to vote.
4.00/5 (9 votes)
6 Apr 2009CPOL2 min read 36.2K   553   22   12
A simple mutlithreaded application using ThreadPool.

Introduction

During some performance testing phases, you often discover that there is a lack in the software performance, and that the solution is not responding, or is not completing its tasks in an acceptable time. This can be caused due to many issues, some related to the code efficiency, or external dependencies, or the execution flow.

In this article, we will see an approach that can help in resolving performance issues. Multi-threading can be a good solution. Multithreading is a popular programming and execution model that allows multiple threads to exist within the context of a single process. These threads share the process' resources but are able to execute independently. The threaded programming model provides developers with a useful abstraction of concurrent execution. However, perhaps the most interesting application of the technology is when it is applied to a single process to enable parallel execution on a multiprocessor system.

Background

You should be familiar with Microsoft .NET, and multi-threading implementation in C#.

Using the code

In this example, we will look at a simple multi-threaded application. We will use the ThreadPool class and the class will be responsible for creating threads, and queuing requests to be picked up later by the created threads. Alternatively, you can do your own thread creation, assignment, and disposing.

First, we will start by creating a parent thread, and assign the delegate to be called. The Start function is a void function with no parameters that will be called once the main thread is created.

C#
Thread parent = new Thread(new ThreadStart(Start));
parent.Start();

The Start function is responsible for creating the threads and queuing the items in the ThreadPool.

C#
private void Start()
{
    // maximum threads cannot be less than the number of CPUs
    ThreadPool.SetMaxThreads(int.Parse(txtMaxThreads.Text), int.Parse(txtMaxIOThreads.Text));
    ThreadPool.SetMinThreads(int.Parse(txtMinThreads.Text), int.Parse(txtMinIOThreads.Text));

    int requestCount = Convert.ToInt32(txtNumberOfRequest.Text);
    AutoResetEvent[] _waitAllEvents; // Array of objects to wait upon.

    // Create an array of objects to wait upon; we need one per thread
    _waitAllEvents = new AutoResetEvent[requestCount];
    // Populate array of waiting objects, one for each work item
    for (int i = 0; i < requestCount; i++)
    {
        _waitAllEvents[i] = new AutoResetEvent(false);
    }
    for (int rqCounter = 0; rqCounter < requestCount; rqCounter++)
    {
        WaitCallback callBack = new WaitCallback(InternalCommand);
        ThreadPool.QueueUserWorkItem(callBack, 
          new Pair(rqCounter.ToString(), _waitAllEvents[rqCounter]));
    }

    // Wait until all our threads have signaled their wait object is done.
    if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
    {
        // WaitAll for multiple handles on an STA thread is not supported.
        // ...so wait on each handle individually.
        foreach (WaitHandle myWaitHandle in _waitAllEvents)
            WaitHandle.WaitAny(new WaitHandle[] { myWaitHandle });
        System.Diagnostics.EventLog.WriteEntry("Finished Execution " + 
                           "STA Mode - Logs are : \n\n", result);
    }
    else
    {
        WaitHandle.WaitAll(_waitAllEvents);
        MessageBox.Show("Finished Execution MTA Mode - Logs are : \n\n" + result);
    }
}

InternalCommand is where the real execution happens, where you can add, delete, or do anything. After you finish, you have to inform the ThreadPool that you finished execution. And, that is done by setting the AutoResetEvent.

C#
private void InternalCommand(object state)
{
    string threadID = (string)((Pair)state).First;
    lock (result)
    {
        result += "Thread with the thread id ";
        result += threadID;
        result += " was called";
        result += "\n";
    }
    AutoResetEvent autoResetEvent = ((Pair)state).Second as AutoResetEvent;
    // Set our wait item to indicate we are done here.
    autoResetEvent.Set();
}

Example execution flow

This example execution flow can be described as follows:

  1. The ThreadPool will be initialized based on the user input.
  2. Based on the request count, the request event handlers will be created.
  3. All request will be queued into the ThreadPool queue, where the ThreadPool will create working threads to handle the requests.
  4. At the execution function, whenever it finishes execution, the handler will be set.
  5. When all event handlers are set, a message box will be shown.

History

  • Version 1.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Program Manager
Jordan Jordan
Self-motivated, creative and results-driven technology executive who is well versed and experienced in leveraging an end-to-end, holistic vision of business objectives to drive full technology / business alignment.

Skilled in grasping business needs and sudden market demand’s shifts by diving into latest business / technology trends, selecting the best fit business model / technology to create a positive reflection on revenue. His multifaceted approach has enabled him to deliver key solutions across a wide range of disciplines including design, development, UX / UI, Business Intelligence.

Technical Specialties are in .Net, Java, Spring Boot, Maven, MS SQL, Oracle, Postgesql, Redis, Javascript, Bootstrap, Angular 2.

Comments and Discussions

 
Generalok article Pin
Donsw11-May-09 8:09
Donsw11-May-09 8:09 
GeneralRe: ok article Pin
Wael Al Wirr11-May-09 19:53
Wael Al Wirr11-May-09 19:53 
Generallock(result) Pin
leeloo9996-Apr-09 21:47
leeloo9996-Apr-09 21:47 
This lock does not really work. I encounter lock problem side effects for > 20 requests. Usage of lock("String") or usage of special lock object doesn't have this effect. Any idea why this happens?
GeneralRe: lock(result) Pin
Wael Al Wirr6-Apr-09 22:43
Wael Al Wirr6-Apr-09 22:43 
AnswerRe: lock(result) Pin
ThaiCoon6-Apr-09 22:57
ThaiCoon6-Apr-09 22:57 
GeneralRe: lock(result) Pin
Wael Al Wirr6-Apr-09 23:28
Wael Al Wirr6-Apr-09 23:28 
GeneralRe: lock(result) Pin
ThaiCoon7-Apr-09 0:25
ThaiCoon7-Apr-09 0:25 
GeneralRe: lock(result) Pin
Wael Al Wirr7-Apr-09 0:34
Wael Al Wirr7-Apr-09 0:34 
GeneralRe: lock(result) Pin
ThaiCoon7-Apr-09 3:10
ThaiCoon7-Apr-09 3:10 
GeneralRe: lock(result) Pin
Wael Al Wirr7-Apr-09 3:31
Wael Al Wirr7-Apr-09 3:31 
GeneralRe: lock(result) Pin
ThaiCoon7-Apr-09 3:55
ThaiCoon7-Apr-09 3:55 
GeneralRe: lock(result) Pin
Wael Al Wirr7-Apr-09 4:05
Wael Al Wirr7-Apr-09 4:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.