C#, MultiThreading

Producer Consumer Problem using locks in C#.Net

Problem Statement

The Producer Consumer problem is a classical Multithreaded problem which involves synchronization among multiple threads which are producing/consuming items from a resource at different speeds.

There are different ways to solve this problem in C#. I would be using the Monitor class for locking and its Wait/Pulse methods for signalling.

The client of the ProducerConsumer Class could use the old Threading API (Thread class) to spin off threads which try to consume/produce items or use TPL to use threads from the ThreadPool.

Code

using System.Collections.Generic;
using System.Linq;
using System.Threading;
 
namespace MultiThreading
{
    internal class ProducerConsumerProblem
    {
        private readonly object _lock = new object();
        private readonly Queue<int> queue = new Queue<int>();
 
 
        public void Produce(int input)
        {
            lock (_lock)
            {
                queue.Enqueue(input);
                Monitor.Pulse(_lock);
            }
        }
 
        public int Consume()
        {
            lock (_lock)
            {
                while (!queue.Any())
                {
                    Monitor.Wait(_lock);
                }
 
                return queue.Dequeue();
            }
        }
    }
}

Test

 [TestMethod]
       public void PoducerConsumerProblem_Should_Succeed()
       {
           var producerConsumerProblem = new ProducerConsumerProblem();
 
           Thread.CurrentThread.Name = "Main Consumer Thread";
           var t1=new Thread(
             () => producerConsumerProblem.Produce(1)) {Name = "Producer Thread"};
           t1.Start();
 
           producerConsumerProblem.Consume();
         
 
           var t2 =new Thread(
               () =>
               {
                   for (int i = 0; i < 10; i++)
                   {
                       producerConsumerProblem.Produce(i);
                   }
                   
               }
               ) {Name = "Producer Thread 2"};
 
           t2.Start();
       }

Final Words

.NET Framework 4.5 has a Concurrent collection called BlockingCollection which solves the same Producer-Consumer problem. In case you are using a former version of the framework, using Monitor is the simplest way to solve the problem. You can also use Semaphores to restrict Threads to a certain number (maybe depending on the cores of your system).

Advertisements
Standard
C#, MultiThreading

Ways to implement MultiThreading in C#

I have been using Threads in C# from quite a while now and it would not be wrong to say that I always mix up APIs in C# which allow to create threads/ use thread pools for that matter.

There are literally many ways to go about Threading in C# and I finally decided to jot down all ways I know so that I don’t end up mixing them again.

Here are the ways with code samples:

         1
         // Passing the method name to be executed in the ctor directly without using ThreadStart delegate
         var thread1 = new Thread(DoSomeWork);
         thread1.Start();
 
         2
         // Passing the ThreadStart delegate  which points to a method to be executed
         var threadStart = new ThreadStart(DoSomeWork);
         var thread2 = new Thread(threadStart);
         thread2.Start();
 
          3
         // Passing the ParametrizedThreadStart delegate  which points to the method to be executed
         var parametrizedThreadStart = new ParameterizedThreadStart(DoSomeWorkWithParameter);
         var thread3 = new Thread(parametrizedThreadStart);
         thread3.Start(2);
 
         4
         // Passing a Lambda expression in the Thread class constructor and subsequently calling the Start method
         var thread4 = new Thread(() =>
         {
             int x = 5;
             for (int i = 0; i < x; i++)
             {
                 Console.WriteLine(i);
             }
         });
 
         thread4.Start();
 
         5
         // Leveraging ThreadPools, call ThreadPool.QueueUserWorkItem passing in the method name to be executed
         ThreadPool.QueueUserWorkItem(DoSomeWorkWithParameter);
         ThreadPool.QueueUserWorkItem(DoSomeWorkWithParameter, 4);
 
            6
         // Using TPL (Task Parallel Library). Create a Task<T>, where T is the return type of the method to be executed.
         Task<string> task = Task.Factory.StartNew<string>(DoSomeStringWork);
         var result = task.Result;
 
           7
        // Instantiating Task class directly
            var task = new Task(
                () =>
                {
                    Console.WriteLine("Worker thread!");
                    Thread.Sleep(1000);
                });
 
            task.Start();

 8
// Using Asynchronous Delegates, also known as the APM pattern 
Func<stringstring> work = DoSomeStringWork;
IAsyncResult res = work.BeginInvoke(“Hello”nullnull);
string result1 = work.EndInvoke(res);
}

Utility Methods:

static void DoSomeWorkWithParameter(object a)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(“Do some work invoked, Thread Id:{0}, i);
}

}

static void DoSomeWork()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(“Do some work invoked, Thread Id:{0}, i);
}

}

static string DoSomeStringWork()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(“Do some work invoked, Thread Id:{0}, i);
}
return “a”;
}

static string DoSomeStringWork(string a)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(“Do some work invoked, Thread Id:{0}, i);
}
return “a”;
}

Standard