使用 C# 的线程池问题

本文关键字:问题 线程 使用 | 更新日期: 2023-09-27 18:37:18

我正在做我的大学项目。主要要求之一是使用multithreading(用户可以选择线程编号)。

我是 C# 的新手,并且基于互联网研究。我选择ThreadPool.

我花了很多时间观察线程如何使用 VS 中的并行监视来操作,我不知道这个东西是如何工作的。例如threadNumber = 10但并行监视仅显示 4 个激活的线程。

这是我的代码:

public void calculateBeta()
    {
        var finished = new CountdownEvent(1);
        for (int i = 0; i < threadNumber; i++)
        {
            finished.AddCount();
            ThreadPool.QueueUserWorkItem(
            (state) =>
            {
                try
                {
                   doSth();
                }
                finally
                {
                    finished.Signal();
                }
            });
        }
        finished.Signal();
        finished.Wait();
    }

我做错了什么?我尝试使用许多不同的线程数值测试此代码,但它没有像我寻找的那样工作。

编辑:

 private void myTask(object index)
    {
            int z = (int)index;
            double[] result = countBeta(createTableB(z), createTableDiagonalA(z));
            int counter = 0;
            if ((rest != 0) && (z == threadNumber - 1))
            {
                for (int j = z * numbersInRow; j < (z + 1) * numbersInRow + rest; j++)
                {
                    N[j] = result[counter];
                    counter++;
                }
            }
            else
            {
                for (int j = z * numbersInRow; j < (z + 1) * numbersInRow; j++)
                {
                    N[j] = result[counter];
                    counter++;
                }
            }
            threads[z] = true;
    }

public void calculateBeta()
    {
        N = new double[num];
        setThreadNumber(2);
        checkThreadNumber();
        setNumberInRow();
        setRest();
        threads = new bool[threadNumber];
        for (int i = 0; i < threadNumber; i++)
        {
            Thread thread = new Thread(this.myTask);
            thread.IsBackground = true;
            thread.Start(i);
        }
        while (!checkThreads())
        {
        }
    }
private bool checkThread()
    {
        bool result = true;
        for (int i = 0; i < threads.Length; i++)
        {
            if (!threads[i])
                result = false;
        }
        return result;
    }
static void Main(string[] args)
    {

        Jacobi jacobi = new Jacobi();
        Console.WriteLine("Metoda Jacobiego");
        Console.WriteLine("Rozwiazywanie ukladu n-rownan z n-niewiadomymi Ax=b");
        jacobi.getNum();
        jacobi.getA();
        jacobi.getB();
        jacobi.calculateBeta();
        jacobi.calculateM();
        jacobi.calculateX();
        jacobi.countNorms();
        Console.ReadLine();
    }

我需要从计算 Beta 到进一步计算的结果。有时线程尚未完成,但程序在没有需要由线程提供的数据的情况下继续前进。我现在正在使用布尔变量,但这个解决方案不是一种优雅的处理方式(创建布尔表,检查是否所有线程都被 fnished)我如何以不同的方式管理它?

使用 C# 的线程池问题

这是因为您正在使用 ThreadPool 来管理您的线程。它将根据许多因素创建一定数量的线程。您可以调整一些设置,但总的来说,当您承诺使用 ThreadPool 来管理您的线程时,您会提交到黑盒。查看 GetMaxThreads 和 GetMinThreads 及其资源库对应项,了解您的一些选项。

查看这篇关于 MSDN 的 ThreadPool 体系结构文章。它为课程的方式和原因提供了良好的背景。但是在介绍性段落中,您将看到这句话,这是您难题的关键:

线程池主要用于减少应用程序数量 线程,并提供工作线程的管理。

如果你想拥有那种快速连续启动 10 个线程的控制,你应该避免 ThreadPool 而只管理线程。下面是一个简单、绝对最小的示例,它启动了十个线程,并为每个线程传递不同的数据,在本例中为索引:

void ButtonClickHandlerOrSomeOtherMethod()  
{
    for (int i=1; i<=10; i++) // using a 1-based index
    {
        new Thread(ThreadTask).Start(i);
    }
}
void ThreadTask(object i) 
{
    Console.WriteLine("Thread " + i + " ID: " + Thread.CurrentThread.ManagedThreadId);
}

和一些示例输出:

线程 1 ID: 19线程 2 ID: 34线程 3 ID: 26线程 4 ID: 5线程 5 ID: 36线程 6 ID: 18线程 7 ID: 9线程 8 ID: 38线程 9 ID: 39线程 10 ID: 40

演示与线程同步并"等待"直到它们全部完成的后续代码:

void ButtonClickHandlerOrSomeOtherMethod() 
{
    // need a collection of threads to call Join after Start(s)
    var threads = new List<Thread>();
    // create threads, add to List and start them
    for (int i=1; i<=10; i++) {
        var thread = new Thread(ThreadTask);
        threads.Add(thread);
        // a background thread will allow main app to exit even
        // if the thread is still running
        thread.IsBackground = true;
        thread.Start(i);
    }
    // call Join on each thread which makes this thread wait on
    // all 10 other threads
    foreach (var thread in threads) 
        thread.Join();
    // this message will not show until all threads are finished
    Console.WriteLine("All threads finished.");
}
void ThreadTask(object i) 
{
    Console.WriteLine("Thread " + i + " ID: " + Thread.CurrentThread.ManagedThreadId);
    // introducing some randomness to how long a task "works on something"
    Thread.Sleep(100 * new Random().Next(0, 10));
    Console.WriteLine("Thread " + i + " finished.");
}

线程池的整个设计是,它不必在每次新项目排队时都创建新的实际线程。 如果池注意到队列中有项目长时间处于挂起状态,则随着时间的推移,它最终将开始启动新线程。 如果您不断用操作使线程池饱和,您将看到实际线程数增加。 它也只会添加新线程,直到限制;根据它的感觉将具有最佳吞吐量。 例如,它将避免创建比内核多得多的线程,假设所有线程都在主动运行 CPU 绑定工作。

使用线程池的想法是,如果您不关心实际线程的数量,而只是希望拥有您拥有的操作的有效吞吐量,从而允许框架在如何最好地优化该工作方面有很大的自由度。 如果您对拥有的线程数有非常具体的要求,则需要手动创建线程,而不是使用池。

// Array of threads launched. 
// This array is useful to trace threads status.
Thread[] threads;
private void myTask(object index)
{
    Console.Write("myTask {0} started'n", index);
    Console.Write("myTask {0} finisced'n", index);
}
public void calculateBeta(UInt16 threadNumber)
{
    // Allocate a new array with size of requested number of threads
    threads = new Thread[threadNumber];
    // For each thread
    for (int i = 0; i < threadNumber; i++)
    {
        // Thread creation
        threads[i] = new Thread(this.myTask);
        // IsBackground set to true grants that the allication can be "killed" without wait for all threads termination
        // This is useful in debug to be sure that an error in task doesn't freeze the app.
        // Leave it to false in release
        #if DEBUG
        threads[i].IsBackground = true;
        #endif
        // Start the thread
        threads[i].Start(i);
    }
    // Waits until all threads complete.
    while (!checkThreads());
}
private bool checkThreads()
{
    bool result = true;
    for (int i = 0; i < threads.Length; i++)
    {
        // If the thread wasn't disposed
        if (threads[i] != null)
        {
            // Check if the thead is alive (means is working)
            if (threads[i].IsAlive == true) 
            {
                result = false;
            }
            else // The thread is not working 
            {
                // Dispose the thread
                threads[i].Join();
                // Set pointer to null to signal that the task was 
                threads[i] = null;
            }
        }
    }
    return result;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    Console.Write("Starting tasks!!'n");
    calculateBeta(10);
    Console.Write("All tasks finished!!'n");
}