代码之家  ›  专栏  ›  技术社区  ›  Greg

如何将这个C#工作线程代码与共享数据变量的主线程解耦?

  •  3
  • Greg  · 技术社区  · 14 年前

    如何修改下面的代码,以便更好地阅读代码:

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

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

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

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

    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);
                        }
                    }
                }
            }
        }
    }
    
    1 回复  |  直到 14 年前
        1
  •  2
  •   Community CDub    8 年前

    这是一个分离关注点的练习,最初我将把这个程序分成 work provider worker . 提供者负责队列和执行控制,而工作者则负责计算。下面的代码是一个粗糙的开始,但它应该让你去。

    将这两个问题分开,并使用构造函数注入已经在可测试性方面取得了成效,现在您可以完全测试了 Worker Program .

    考虑到你的应用程序的进一步开发,我强烈建议你 the Task Parallel Library 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);
                }
            }
        }
    
    }