1

要求:-在任何给定时间点,只有 4 个线程应该调用四个不同的函数。一旦这些线程完成,下一个可用线程应该调用相同的函数。

当前代码:-这似乎是实现此类目标的最糟糕的方法。While(True) 会导致不必要的 CPU 峰值,运行以下代码时我可以看到 CPU 上升到 70%。

问题:-一旦前 4 个工作线程完成处理,我如何使用 AutoResetEventHandler 向主线程 Process() 函数发出信号以再次启动下 4 个线程,而不会浪费 CPU 周期。请建议

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以更简单的方式实现您想要的。如果您运行下面的代码,您会注意到在每个线程终止后写入了一个条目,并且只有在所有四个线程都终止后才"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;
}

另一件事是,从您问题的文本要求部分,我相信一批四个新线程应该只在之前的四个线程完成后才开始。但是,您发布的代码与该要求不兼容,因为它在前一个线程终止后立即启动一个新线程。您应该澄清您的要求到底是什么。


更新:

如果您想在四个线程之一终止后立即启动一个线程,您仍然可以使用 TPL 而不是显式启动新线程,但您可以使用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 回答