resthere
resthere

Reputation: 129

Code Help for ThreadPool

Have created a class which implements ThreadPool. The code is as below:

public sealed class PyeThreadPool :

  IDisposable
{
    private readonly object _lock = new object();
    private readonly int _minThreadCount;
    private readonly int _maxThreadCount;
    private readonly Queue<Action> _queue = new Queue<Action>();
    private int _totalThreadCount;
    private int _waitingThreadCount;
    private bool _disposed;

    public PyeThreadPool(int minThreadCount, int maxThreadCount)
    {
        if (minThreadCount < 0)
            throw new ArgumentOutOfRangeException("minThreadCount");

        if (maxThreadCount < 1 || maxThreadCount < minThreadCount)
            throw new ArgumentOutOfRangeException("maxThreadCount");

        _minThreadCount = minThreadCount;
        _maxThreadCount = maxThreadCount;


    }
    public void Dispose()
    {
        lock (_lock)
        {
            _disposed = true;

            // if there are thread waiting, they should stop waiting.
            if (_waitingThreadCount > 0)
                Monitor.PulseAll(_lock);
        }
    }

    /// <summary>
    /// Executes an action in a parallel thread. 
    /// </summary>
    public void RunParallel(Action action)
    {


            if (action == null)
                throw new ArgumentNullException("action");

            lock (_lock)
            {
                if (_disposed)
                    throw new ObjectDisposedException(GetType().FullName);

                bool queued = false;
                if (_waitingThreadCount == 0)
                {
                    if (_totalThreadCount < _maxThreadCount)
                    {
                        _totalThreadCount++;

                        var thread = new Thread(_ThreadRun);
                        thread.Name = "Worker Thread";
                        thread.Start(action);
                        queued = true;
                    }
                }

                if (!queued)
                {
                    _queue.Enqueue(action);
                    Monitor.Pulse(_lock);
                }
            }

    }
    private void _ThreadRun(object firstAction)
    {
        Action action = (Action)firstAction;
        firstAction = null;
        // we always start a new thread with an action, so we get it immediately.
        // but, as we don't know what that action really holds in memory, we set
        // the initial action to null, so after it finishes and a new action is get,
        // we will let the GC collect it.

        while (true)
        {
            action();

            lock (_lock)
            {
                if (_queue.Count == 0)
                {
                    // we started waiting, so new threads don't need to be created.
                    _waitingThreadCount++;


                    while (_queue.Count == 0)
                    {

                        if (_disposed)
                            return;


                        if (_totalThreadCount > _minThreadCount)
                        {
                            _totalThreadCount--;
                            _waitingThreadCount--;
                            return;
                        }


                        action = null;
                        Monitor.Wait(_lock);
                    }

                    // we finished waiting.
                    _waitingThreadCount--;
                }

                action = _queue.Dequeue();
                // we just get a new action, and we will release the lock and return
                // to the while, where the action will be executed.
            }
        }
    }
}

I have tried to use this and the test code is as:

    PyeThreadPool MyPool;

    int x = 1;

    protected void Page_Load(object sender, EventArgs e)

    {
        MyPool = new PyeThreadPool(4, 6);

    }

    void showMessage(string message)

    {

        TxtMessage.Text = message;

    }


    protected void BtnStartThread_Click(object sender, EventArgs e)

    {

        x++;
        int arg = x;
        MyPool.RunParallel(() =>
        {
            showMessage(arg.ToString());
        });

     }

Problem is:

(1) When I execute this either in debug or release mode I do not see the result in textbox, on the other hand I see the result when I step through. What am I missing here, why I can not see the output.

(2) The RunParallel method shows only one thread even if I have set maxcount to more than 1. Is there any code logic missing or is it because the test application is simple?

Thanks !

Upvotes: 1

Views: 102

Answers (2)

Keith
Keith

Reputation: 1129

The problem is you are attempting to update a UI control from a background thread. Not allowed.

You need to do a BeginInvoke or Invoke in your ShowMessage function.

Upvotes: 0

Parimal Raj
Parimal Raj

Reputation: 20595

You should have a look at SmartThreadPool library. It is one of the best alternative to ThreadPool.

Its features (copied from source link)

Smart Thread Pool is a thread pool written in C#. The implementation was first based on Stephan Toub's thread pool with some extra features, but now, it is far beyond the original. Here is a list of the thread pool features:

  • The number of threads dynamically changes according to the workload on the threads in the pool. Work items can return a value.
  • A work item can be cancelled if it hasn't been executed yet.
  • The caller thread's context is used when the work item is executed (limited).
  • Usage of minimum number of Win32 event handles, so the handle count of the application won't explode.
  • The caller can wait for multiple or all the work items to complete.
  • A work item can have a PostExecute callback, which is called as soon the work item is completed.
  • The state object that accompanies the work item can be disposed automatically.
  • Work item exceptions are sent back to the caller.
  • Work items have priority.
  • Work items group.
  • The caller can suspend the start of a thread pool and work items group.
  • Threads have priority.
  • Threads have initialization and termination events.
  • WinCE platform is supported (limited).
  • Action and Func generic methods are supported.
  • Silverlight is supported.
  • Mono is supported.
  • Performance counters (Windows and internal).
  • Work item timeout (passive).
  • Threads ApartmentState
  • Threads IsBakcground
  • Threads name template
  • Windows Phone is supported (limited)
  • Threads MaxStackSize

Upvotes: 1

Related Questions