3

我怎样才能修改下面的代码,以便更好地提高代码的可读性:

a)将“workThreadMethod()”移动到它自己的类中

b)此工作线程类中没有任何代码引用主“程序”类中的静态变量

c)以上是主要的两个要求,但是我希望作为副作用,这将确保工作线程类方法的可测试性更容易测试,并且理想情况下适合通过 IOC 进行测试(例如 Ninject)概念[如果这没有意义,那么出于问题的目的忽略这一点]

我不确定要解决的主要挑战是如何处理原始线程和新线程之间的两个不同的共享变量(其中一个是新线程添加到的 ConcurrentQueue,另一个是原始线程添加的布尔变量线程用于向新线程指示何时停止)

using System.Collections.Concurrent;
using System.Diagnostics;
using System.Threading;

namespace TestConsoleApp
{
    class Program
    {
        // Main Thread uses to indicate to New Thread to stop
        private static bool _shouldStop = false;

        // New Thread uses to pass back result to Main Thread
        private static long _results = 0;

        // Main Thread passes ongoing updates to New Thread via this queue
        private static ConcurrentQueue<long> _workQueue = new ConcurrentQueue<long>();

        static void Main(string[] args)
        {
            var p = new Program();
            p.TestThreads();
        }

        public void TestThreads()
        {
            _shouldStop = false;
            var workThread = new Thread(workThreadMethod);
            workThread.Start();

            for (int i = 0; i < 100; i++)
            {
                _workQueue.Enqueue(i);   // Add test data to queue
                Debug.WriteLine("Queue  : " + i);
                Thread.Sleep(10);
            }

            Thread.Sleep(5000);

            _shouldStop = true;
            workThread.Join();
            Debug.WriteLine("Finished TestThreads.  Result = " + _results);
        }


        // Dequeuer Methods
        private void workThreadMethod()
        {
            // Update Summary
            while (!_shouldStop)
            {
                if (_workQueue.Count == 0)
                {
                    Thread.Sleep(10);
                }
                else
                {
                    long currentValue;
                    bool worked = _workQueue.TryDequeue(out currentValue);
                    if (worked)
                    {
                        _results += currentValue;
                        Debug.WriteLine("DeQueue: " + currentValue);
                    }
                }
            }
        }
    }
}
4

1 回答 1

2

This is an exercise in separation of concerns, and initially I would split this program into a work provider and worker. The provider is responsible for the queue and execution control while the worker should do calculation. The following code is a crude start but it should get you going.

Splitting up the two concerns and using constructor injection already pays of in testability, you can now fully test Worker without involving Program.

Note: considering further development of your app I would strongly suggest that you look into the Task Parallel Library. Using a library such as the TPL enables you to take advantage of multi-core processors without having to deal with the complexities of thread allocation and work scheduling. More resources on the TPL is discussed here.

public interface IWorkProvider
{
    bool ShouldStop { get; }
    long? GetWork();
}

public class Program : IWorkProvider
{
    // Main Thread uses to indicate to New Thread to stop
    private static bool _shouldStop = false;

    // Main Thread passes ongoing updates to New Thread via this queue
    private static ConcurrentQueue<long> _workQueue = new ConcurrentQueue<long>();

    public bool ShouldStop { get { return _shouldStop; } }

    public long? GetWork()
    {
        long currentValue;
        bool worked = _workQueue.TryDequeue(out currentValue);
        if (worked)
            return currentValue;
        return null;
    }
}

public class Worker
{
    private long _results;
    private readonly IWorkProvider _workProvider;

    public long Results { get { return _results; }}

    public Worker(IWorkProvider workProvider)
    {
        _workProvider = workProvider;
    }

    public void DoWork()
    {
        // Update Summary
        while (!_workProvider.ShouldStop)
        {
            long? work = _workProvider.GetWork();
            if (work.HasValue)
            {
                _results += work.Value;
                Debug.WriteLine("DeQueue: " + work.Value);
            }
            else
            {
                Thread.Sleep(10);
            }
        }
    }

}
于 2010-08-10T09:00:59.843 回答