1

要件:-任意の時点で、4 つのスレッドだけが 4 つの異なる関数を呼び出す必要があります。これらのスレッドが完了するとすぐに、次に利用可能なスレッドが同じ関数を呼び出す必要があります。

現在のコード:-これは、このようなことを達成するための最悪の方法のようです。While(True) は不必要な CPU スパイクを引き起こし、次のコードを実行すると CPU が 70% に上昇することがわかりました。

質問 :- AutoResetEventHandler を使用してメイン スレッドの Process() 関数にシグナルを送信し、最初の 4 つのワーカー スレッドの処理が完了したら、CPU サイクルを無駄にすることなく次の 4 つのスレッドを再度開始するにはどうすればよいですか。提案してください

public class Demo
{
    object protect = new object();
    private int counter;
    public void Process()
    {
        int maxthread = 4;
        while (true)
        {
            if (counter <= maxthread)
            {
                counter++;
                Thread t = new Thread(new ThreadStart(DoSomething));
                t.Start();
            }
        }
    }
    private void DoSomething()
    {
        try
        {
            Thread.Sleep(50000); //simulate long running process
        }
        finally
        {
            lock (protect)
            {
                counter--;
            }
        }
    }
4

1 に答える 1

2

TPLを使用すると、より簡単な方法で目的を達成できます。以下のコードを実行すると、各スレッドが終了した後、4つのスレッドすべてが終了した後にのみ"Finished batch"エントリが書き込まれることがわかります。

このサンプルでは、​​を使用してTask.WaitAllすべてのタスクの完了を待機します。コードは説明の目的でのみ無限ループを使用しhasPendingWorkます。必要な場合にのみタスクの新しいバッチを開始するように、要件に基づいて条件を計算する必要があります。

例えば:

private static void Main(string[] args)
{
    bool hasPendingWork = true;
    do
    {
        var tasks = InitiateTasks();

        Task.WaitAll(tasks);

        Console.WriteLine("Finished batch...");
    } while (hasPendingWork);
}

private static Task[] InitiateTasks()
{
    var tasks = new Task[4];

    for (int i = 0; i < tasks.Length; i++)
    {
        int wait = 1000*i;

        tasks[i] = Task.Factory.StartNew(() =>
        {
            Thread.Sleep(wait);
            Console.WriteLine("Finished waiting: {0}", wait);
        });
    }

    return tasks;
}

もう1つ、あなたの質問のテキスト要件のセクションから、4つの新しいスレッドのバッチは、以前の4つのスレッドがすべて完了した後にのみ開始する必要があると思います。ただし、投稿したコードは、前のスレッドが終了した直後に新しいスレッドを開始するため、その要件と互換性がありません。要件を正確に明確にする必要があります。


アップデート:

4つのスレッドのいずれかが終了した直後にスレッドを開始する場合は、新しいスレッドを明示的に開始する代わりにTPLを使用できますが、を使用して実行中のスレッドの数を4つに制限できますSemaphoreSlim。例えば:

private static SemaphoreSlim TaskController = new SemaphoreSlim(4);

private static void Main(string[] args)
{
    var random = new Random(570);

    while (true)
    {
        // Blocks thread without wasting CPU
        // if the number of resources (4) is exhausted
        TaskController.Wait();

        Task.Factory.StartNew(() =>
        {
            Console.WriteLine("Started");
            Thread.Sleep(random.Next(1000, 3000));
            Console.WriteLine("Completed");
            // Releases a resource meaning TaskController.Wait will unblock
            TaskController.Release();
        });
    }
}
于 2013-01-30T09:47:42.653 に答える