在C#中的for循环中创建多个线程

本文关键字:创建 线程 循环 中的 for | 更新日期: 2023-09-27 17:59:21

我有一个测试客户端,可以在其中指定要创建的线程数。我根据用户选择的数字运行for循环并启动线程。我将线程存储在列表中,以便在稍后阶段监视/终止线程。当我运行循环时,我可以看到所有线程都有ThreadState.Running。然而,我总是看到创建的线程更少。请帮助

    private void btnReadMTNPServer_Click(object sender, EventArgs e)
    {
        DisableTestButtons();
        SetValuesFromControls();
        ResetThreads();
        _metrics.Clear();
        _runTest = true;
        _keys = GetTestKeysList();
        for (var i = 0; i < _numClients; i++)
        {
            var index = i;
            TestThreads.Add(RunNamedPipeThread(index));
            AppendConsoleText(string.Format("ThreadState: {0}", TestThreads[index].ThreadState));
            Thread.Sleep(50);
        }
        AppendConsoleText(string.Format("Starting {0} Clients. Each Reading {1} Keys", TestThreads.Count, nudTestReadKeyCount.Value));
    }

    private Thread RunNamedPipeThread(int i)
    {
        var thread = new Thread(RunNamedPipeServerTest)
        {
            Name = i.ToString("D3")
            //IsBackground = true
        };
        while (thread.ThreadState != ThreadState.Running)
            thread.Start(i);
        return thread;
    }
private void RunNamedPipeServerTest(object i)
    {
        var id = (int)i;
        var iteration = 0;
        var list = new List<short>();
        var client = new PipeClient("DHM");
        {
            client.Start();
            while (_runTest)
            {
                var startTimeStamp = DateTime.Now;
                foreach (var key in _keys.TakeWhile(key => _runTest))
                {
                    list.Add(client.GetValue(key));
                    if (_delayPerKey > 0)
                        Thread.Sleep(_delayPerKey);
                }
                var finishTimeStamp = DateTime.Now;
                //Keep the client connected using KeepAlive.
                client.KeepAlive();
                _metrics.Add(new PerformanceMetric(id.ToString("D3"), startTimeStamp, finishTimeStamp));
                AppendConsoleText(string.Format("{3}:{0}:Start:{1}, Took {2} ms", id.ToString("D3"), startTimeStamp.ToString("mm:ss.ffff"), finishTimeStamp.Subtract(startTimeStamp).TotalMilliseconds, iteration++));
                //Wait before sending request for data.
                Thread.Sleep(_testFrequency);
            }
            client.Stop();
        }
        if (cbxDisplayValues.Checked)
            AppendConsoleText(string.Format("{0}", string.Join(",", list)));
    }

    private void ResetThreads()
    {
        if (TestThreads == null)
            TestThreads = new List<Thread>();
        _runTest = false;
        TestThreads.ForEach(t => t.Abort());
        TestThreads.Clear();
    }

    private void AppendConsoleText(string text)
    {
        if (txtConsole.InvokeRequired)
        {
            Invoke(new MethodInvoker(() => txtConsole.AppendText(string.Format("{0}{1}", text, Environment.NewLine))));
        }
        else
        {
            txtConsole.AppendText(string.Format("{0}{1}", text, Environment.NewLine));
        }
    }

这是我经常在文本框中看到的结果。有5个线程正在运行,但只有3个线程正在写入。不过,这种情况是随机发生的。有时5个人按预期写,有时他们没有。

ThreadState: Running
ThreadState: Running
ThreadState: Running
ThreadState: Running
ThreadState: Running
Starting 5 Clients. Each Reading 1000 Keys
0:002:Start:53:55.5393, Took 187.4653 ms
0:003:Start:53:55.6331, Took 125.0191 ms
0:004:Start:53:55.7424, Took 109.4014 ms
1:002:Start:53:58.7539, Took 62.4642 ms
1:003:Start:53:58.7851, Took 62.5031 ms
1:004:Start:53:58.8789, Took 46.8898 ms
2:002:Start:54:01.8316, Took 62.4693 ms
2:003:Start:54:01.8629, Took 125.0298 ms
2:004:Start:54:01.9410, Took 93.7239 ms
3:002:Start:54:04.9149, Took 52.3515 ms
3:003:Start:54:04.9985, Took 62.5211 ms
3:004:Start:54:05.0454, Took 46.8765 ms
4:002:Start:54:07.9954, Took 46.77 ms
4:003:Start:54:08.0736, Took 46.7811 ms
4:004:Start:54:08.1203, Took 46.8748 ms
5:002:Start:54:11.0636, Took 46.7713 ms
5:003:Start:54:11.1417, Took 62.4283 ms
5:004:Start:54:11.1885, Took 46.8748 ms
6:002:Start:54:14.1308, Took 39.5712 ms
6:003:Start:54:14.2173, Took 54.1113 ms
6:004:Start:54:14.2486, Took 47.9687 ms
7:002:Start:54:17.1964, Took 51.7147 ms
7:003:Start:54:17.2795, Took 62.3954 ms
7:004:Start:54:17.3107, Took 46.8722 ms
8:002:Start:54:20.2644, Took 46.77 ms
8:003:Start:54:20.3581, Took 46.77 ms
8:004:Start:54:20.3738, Took 46.7721 ms
9:002:Start:54:23.3386, Took 46.77 ms
9:003:Start:54:23.4324, Took 46.7704 ms
9:004:Start:54:23.4480, Took 46.7969 ms

编辑#1:发生的情况是,有5个线程表示它们正在运行。然而,如果你仔细看下面写着"启动5个客户"的行。每个Reading 1000 Keys’每个迭代0、1、2…每三秒有3个条目。我预计5个线程正在运行。

根据@jackncoke,我确实尝试过使用这个而不是for循环:

Parallel.For(0, _numClients, i => RunNamedPipeServerTest(i)); 

出于某种原因,它只创建了一个线程。

然后我也尝试了:

Parallel.For(0, _numClients, i => RunNamedPipeThread(i));

这是可行的,但是它仍然没有创建正确数量的线程。此外,如果您查看方法RunNamedPipeThread,我仍然显式地为RunNamedPipeServerTest创建线程。

在C#中的for循环中创建多个线程

考虑使用Parallel.For,而不是创建大量自己的线程。它为您处理任务和线程调度,您可以通过指定ParallelOptions来指定要使用的最大线程数量,以防止操作占用系统的所有资源。

除此之外,请确保您使用的是并发集合。这些集合针对您的场景进行了优化,并允许您(在大多数情况下)不必担心锁争用、死锁和大量其他潜在危险。

出于某种原因,它只创建了一个线程。

虽然Parallel.ForParallel.ForEach可能调度多个线程,但这并不一定意味着它总是会,正如文档所述:

执行for(Visual Basic中的for)循环,其中的迭代可以并行运行

一般来说,如果您使用并发集合,并且工作负载是可并行的,则运行时将决定向其抛出多个线程。