3

コードを読みやすくするために、以下のコードを変更するにはどうすればよいですか?

a)「workThreadMethod()」を独自のクラスに移動します

b)このワーカースレッドクラスにメインの「プログラム」クラスからの静的変数を参照するコードがない

c)上記は主な2つの要件ですが、副作用として、テスト容易性のためにワーカースレッドクラスメソッドのテストが容易になり、理想的にはIOC(Ninjectなど)を介したテストに役立つことを期待しています。コンセプト[これが意味をなさない場合は、質問の目的のためにこの点を無視してください]

解決についてよくわからない主な課題は、元のスレッドと新しいスレッドの間の2つの異なる共有変数(1つは新しいスレッドが追加するConcurrentQueue、もう1つは元のスレッドが追加する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);
                    }
                }
            }
        }
    }
}
4

1 に答える 1

2

これは関心の分離の演習であり、最初はこのプログラムをとに分割しwork providerますworker。ワーカーが計算を行う間、プロバイダーはキューと実行制御を担当します。次のコードは大雑把なスタートですが、うまくいくはずです。

Worker2つの懸念事項を分割し、コンストラクターインジェクションを使用すると、すでにテストの可能性が高くなります。これで、を使用せずに完全にテストできます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);
            }
        }
    }

}
于 2010-08-10T09:00:59.843 に答える