views:

74

answers:

2

Example for threading queue book "Accelerated C# 2008" (CrudeThreadPool class) not work correctly. If I insert long job in WorkFunction() on 2-processor machine executing for next task don't run before first is over. How to solve this problem? I want to load the processor to 100 percent

public class CrudeThreadPool
{
    static readonly int MAX_WORK_THREADS = 4;
    static readonly int WAIT_TIMEOUT = 2000;
    public delegate void WorkDelegate();

    public CrudeThreadPool()
    {
        stop = 0;
        workLock = new Object();
        workQueue = new Queue();
        threads = new Thread[MAX_WORK_THREADS];
        for (int i = 0; i < MAX_WORK_THREADS; ++i)
        {
            threads[i] = new Thread(new ThreadStart(this.ThreadFunc));
            threads[i].Start();
        }

    }


    private void ThreadFunc()
    {
        lock (workLock)
        {
            int shouldStop = 0;
            do
            {
                shouldStop = Interlocked.Exchange(ref stop, stop);
                if (shouldStop == 0)
                {
                    WorkDelegate workItem = null;

                    if (Monitor.Wait(workLock, WAIT_TIMEOUT))
                    {
                        // Process the item on the front of the queue
                        lock (workQueue)
                        {
                            workItem = (WorkDelegate)workQueue.Dequeue();
                        }
                        workItem();
                    }
                }
            } while (shouldStop == 0);
        }
    }

    public void SubmitWorkItem(WorkDelegate item)
    {
        lock (workLock)
        {

            lock (workQueue)
            {
                workQueue.Enqueue(item);
            }
            Monitor.Pulse(workLock);
        }
    }

    public void Shutdown()
    {
        Interlocked.Exchange(ref stop, 1);
    }
    private Queue workQueue;
    private Object workLock;
    private Thread[] threads;
    private int stop;
}

public class EntryPoint
{
    static void WorkFunction()
    {
        Console.WriteLine("WorkFunction() called on Thread 0}", Thread.CurrentThread.GetHashCode());
        //some long job
        double s = 0;
        for (int i = 0; i < 100000000; i++)
            s += Math.Sin(i);
    }

    static void Main()
    {
        CrudeThreadPool pool = new CrudeThreadPool();
        for (int i = 0; i < 10; ++i)
        {
            pool.SubmitWorkItem(
            new CrudeThreadPool.WorkDelegate(EntryPoint.WorkFunction));
        }
        pool.Shutdown();
    }
}
A: 

It's hard to tell because there's no indentation, but it looks to me like it's executing the work item while still holding workLock - which is basically going to serialize all the work.

If at all possible, I suggest you start using the Parallel Extensions framework in .NET 4, which has obviously had rather more time spent on it. Otherwise, there's the existing thread pool in the framework, and there are other implementations around if you're willing to have a look. I have one in MiscUtil although I haven't looked at the code for quite a while - it's pretty primitive.

Jon Skeet
if only our employers allowed us to pick up the new framework the moment it was released. In the real world we have to worry about support min spec machines and old operations systems which may or may not be supported by .net 4
trampster
+3  A: 

I can see 2 problems:

  • Inside ThreadFunc() you take a lock(workLock) for the duration of the method, meaning your threadpool is no longer async.

  • in the Main() method, you close down the threadpool w/o waiting for it to finish. Oddly enough that is why it is working now, stopping each ThreadFunc after 1 loop.

Henk Holterman