Как я могу отделить этот код рабочего потока C # от основного потока для общих переменных данных? - PullRequest
3 голосов
/ 09 августа 2010

Как я мог изменить приведенный ниже код так, чтобы я мог, для лучшей читаемости в коде:

а) переместить "workThreadMethod ()" в его собственный класс

b) не иметь никакого кода в этом справочнике статических переменных класса рабочего потока из основного класса "Program"

c) вышеприведенные два основных требования, однако я надеюсь, что в качестве побочного эффекта это обеспечит, что для тестируемости методы класса рабочих потоков будет проще для тестирования, и в идеале пригодно для тестирования через 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 Ответ

2 голосов
/ 10 августа 2010

Это упражнение по разделению интересов, и первоначально я бы разделил эту программу на work provider и worker.Поставщик отвечает за очередь и контроль выполнения, в то время как работник должен выполнить расчет.Следующий код - грубое начало, но оно должно помочь вам.

Разделив две проблемы и используя инжектор конструктора, который уже окупается в тестируемости, теперь вы можете полностью протестировать Worker без участия Program.

Примечание: , учитывая дальнейшее развитие вашего приложения, я настоятельно рекомендую вам изучить параллельную библиотеку задач .Использование библиотеки, такой как TPL, позволяет вам использовать преимущества многоядерных процессоров, не сталкиваясь со сложностями распределения потоков и планирования работы.Дополнительные ресурсы по 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);
            }
        }
    }

}
...