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

时间:2015-06-23 21:11:04

标签: c# multithreading

我有一个测试客户端,我可以在其中指定要创建的线程数。我根据用户选择的数字运行for循环并启动我的线程。我将线程存储在List中,以便我可以在稍后阶段监视/终止线程。当我运行循环时,我可以看到所有线程都有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个客户”这一行的下方。每个阅读1000键&#39;每次迭代0,1,2 ...每3秒有3个条目。我期待5个线程正在运行。

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

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

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

然后我也试过了:

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

这可行,但它仍然无法创建正确数量的线程。另外,如果您查看方法 RunNamedPipeThread ,我仍然明确地为 RunNamedPipeServerTest 创建线程。

1 个答案:

答案 0 :(得分:1)

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

最重要的是确保您使用Concurrent Collection。这些集合针对您的场景进行了优化,并允许您(大多数情况下)不担心锁争用,死锁和过多的其他潜在危险。

  

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

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

  

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

一般来说,如果使用并发集合并且工作负载可以兼容,则运行时将决定在其上抛出多个线程。