3

Scenario

I have a background worker in my application that runs off and does a bunch of processing. I specifically used this implementation so as to keep my User Interface fluid and prevent it from freezing up. I want to keep the background worker, but inside that thread, spawn off ONLY 3 MORE threads - making them share the processing (currently the worker thread just loops through and processes each asset one-by-one. However I would like to speed this up but using only a limited number of threads.

Question

Given the code below, how can I get the loop to choose a thread that is free, and then essentially wait if there isn't one free before it continues.

CODE

        foreach (KeyValuePair<int, LiveAsset> kvp in laToHaganise)
        {

             Haganise h = new Haganise(kvp.Value,
                                      busDate,
                                      inputMktSet,
                                      outputMktSet, 
                                      prodType,
                                      noOfAssets, 
                                      bulkSaving);

             h.DoWork();

         }

Thoughts

I'm guessing that I would have to start off by creating 3 new threads, but my concern is that if I'm instantiating a new Haganise object each time - how can I pass the correct "h" object to the correct thread.....

  Thread firstThread = new Thread(new ThreadStart(h.DoWork));
  Thread secondThread =new Thread(new ThreadStart(h.DoWork));
  Thread thirdThread = new Thread(new ThreadStart(h.DoWork));

Help greatly appreciated.

2
  • Unless you're using external resources that are causing your original thread to delay, there is no guarantee dividing the work into three or more threads would be beneficial. Just a thought for you. Commented Apr 9, 2010 at 8:15
  • Why to limit your threads when you can use threadpool? Did you give a try to parallel extensions? Commented Apr 9, 2010 at 8:21

2 Answers 2

2

Depending on the size of the job the thread has to do, ThreadPool.QueueUserWorkItem may be a good option. That will create a thread and put it in a queue and execute it when there is thread in the pool available.

Alternatively you could create your own type of Pool which has 3 threads and use ManualResetEvent to determine when a particular thread is finished.

Sign up to request clarification or add additional context in comments.

Comments

1

Two possibilities:

Here is a working example, that selects the next free worker:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        private static List<MyWorker> _Workers;

        static void Main(string[] args)
        {
            _Workers = new List<MyWorker>();

            for (int i = 0; i < 5; i++)
            {
                _Workers.Add(CreateDefaultWorker(i));
            }

            StartJobs(20000);
            Console.ReadKey();
        }

        private static void StartJobs(int runtime)
        {
            Random rand = new Random();
            DateTime startTime = DateTime.Now;

            while (DateTime.Now - startTime < TimeSpan.FromMilliseconds(runtime))
            {
                var freeWorker = GetFreeWorker();

                if (freeWorker != null)
                {
                    freeWorker.Worker.RunWorkerAsync(new Action(() => DoSomething(freeWorker.Index, rand.Next(500, 2000))));
                }
                else
                {
                    Console.WriteLine("No free worker available!");
                    Console.WriteLine("Waiting for free one...");
                    WaitForFreeOne();
                }
            }
        }

        private static MyWorker GetFreeWorker()
        {
            foreach (var worker in _Workers)
            {
                if (!worker.Worker.IsBusy)
                    return worker;
            }

            return null;
        }

        private static void WaitForFreeOne()
        {
            while (true)
            {
                foreach (var worker in _Workers)
                {
                    if (!worker.Worker.IsBusy)
                        return;
                }
                Thread.Sleep(1);
            }
        }

        private static MyWorker CreateDefaultWorker(int index)
        {
            var worker = new MyWorker(index);

            worker.Worker.DoWork += (sender, e) => ((Action)e.Argument).Invoke();
            worker.Worker.RunWorkerCompleted += (sender, e) => Console.WriteLine("Job finished in worker " + worker.Index);

            return worker;
        }

        static void DoSomething(int index, int timeout)
        {
            Console.WriteLine("Worker {1} starts to work for {0} ms", timeout, index);
            Thread.Sleep(timeout);
        }
    }

    public class MyWorker
    {
        public int Index { get; private set; }
        public BackgroundWorker Worker { get; private set; }

        public MyWorker(int index)
        {
            Index = index;
            Worker = new BackgroundWorker();
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.