简体   繁体   English

如何将此C#工作线程代码与主线程中的共享数据变量分离?

[英]How can I decouple this C# worker thread code from the main thread for shared data variables?

How could I modify the below code such that I could, for better readability in code: 为了更好的代码可读性,我怎么能修改下面的代码呢?

a) move the "workThreadMethod()" into it's own class a)将“workThreadMethod()”移动到它自己的类中

b) not have any code in this worker thread class reference static variables from the main "Program" class b)此工作线程类中没有任何代码引用主“Program”类的静态变量

c) the above are the main two requirements, however I'm hoping that as a side effect this would then ensure that for testability the worker thread class methods would be easier to test and ideally lend itself to testing via the IOC (eg Ninject) concept [if this doesn't make sense then ignore this point for the purpose of the question] c)以上是主要的两个要求,但是我希望作为一个副作用,这将确保为了可测试性,工作者线程类方法将更容易测试并且理想地适合通过IOC进行测试(例如Ninject)概念[如果这没有意义,那么为了问题的目的忽略这一点]

The main challenge that I'm not sure about re solving is how to handle the two different shared variables between the originating thread & new thread (one of them a ConcurrentQueue which the new thread adds to, and the other a bool variable that the original thread uses to indicate to the new thread when to stop) 我不确定要解决的主要挑战是如何处理原始线程和新线程之间的两个不同的共享变量(其中一个是新线程添加的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);
                    }
                }
            }
        }
    }
}

This is an exercise in separation of concerns, and initially I would split this program into a work provider and worker . 这是一个关注点分离的练习,最初我会把这个程序分成一个work providerworker 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 . 拆分这两个问题并使用构造函数注入已经支付了可测试性,您现在可以在不涉及Program情况下完全测试Worker

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. 使用诸如TPL之类的库使您可以利用多核处理器,而无需处理线程分配和工作调度的复杂性。 More resources on the TPL is discussed here . 这里讨论有关TPL的更多资源。

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);
            }
        }
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM