嵌套线程的 for 循环中索引溢出

问题描述 投票:0回答:1

我正在编写一个测试实用程序(WinForm)来检查网站的性能。为此,我设置了要发出的多个请求,以及与请求关联的参数列表。我可以将请求设置为并行或按顺序发生。

如果我按顺序工作,一切都很好,但如果我并行工作,我会遇到 for 循环的奇怪问题。 我知道我可能会使用 Parallel.For,但是因为我正在调查另一个与并行性相关的错误,所以我临时使用了 regualr for,直接执行嵌套操作或使用 Task.Run()。

这里有问题的代码:

private void Run()
{
    ConcurrentBag<long> callTimes = new ConcurrentBag<long>();
    int httpErrors = 0;
    int progress = 0;

    string uri = txtUrl.Text ?? string.Empty;
    if (string.IsNullOrWhiteSpace(uri))
        return;

    Func<List<string>,int,long> testCall = (p,i) =>
    {
        try
        {
            using (var client = new HttpClient())
            {
                Stopwatch timer = new Stopwatch();
                timer.Start();

                string actualUrl = string.Format(uri, p.ToArray());
                var getTask = client.GetAsync(actualUrl);
                getTask.Wait();

                timer.Stop();

                var result = getTask.Result;
                if (result == null || (int)result.StatusCode >= 400)
                {
                    txtErrors.ThreadSafeAppendText($"Connection error {(result?.StatusCode.ToString() ?? "NULL")}'\r\n");
                    Interlocked.Increment(ref httpErrors);
                }

                return timer.ElapsedMilliseconds;
            }
        }
        catch ( Exception actionErr)
        {
            txtErrors.ThreadSafeAppendText($"Error while execution callAction {i} with parameters '{string.Join(", " , p)}' : \r\n" + actionErr.Message);
        }

        return -1;
    };

    try
    {
        List<List<string>> parameters = this.ParseParameters();
        int parametersCount = parameters.Count;
        int executions = (int)updRequests.Value;

        //used to randomly access parameters in a way suitable also for the parallel scenario (i precompute all the random number i need while parallel processing is not yet started)
        Random rng = new Random();
        List<int> randoms = new List<int>();
        for (int i = 0; i < executions; i++)
            randoms.Add(rng.Next(0, parametersCount));

        //randoms.Count is guaranteed to be equal to executions 


        for ( int index = 0; index < executions; index++)
        {
            Action parallelAction = () =>
            {
                int currentIndex = index;
                List<string> currentParameter = parameters[randoms[currentIndex] % parametersCount]; //<<--- strange overflow here currentIndex >= executions
                callTimes.Add(testCall(currentParameter, currentIndex));

                Interlocked.Increment(ref progress);

                if (progress % 10 == 0)
                    prbProgress.ThreadSafeAction(this.RefreshProgressBar, progress, executions);
            };

            if (chkParallelExecution.Checked)
                Task.Run(parallelAction);
            else
                parallelAction();
        }


        this.Reporting(callTimes, httpErrors);
    }
    catch (Exception err)
    {
        txtErrors.ThreadSafeAppendText($"Error while running stress test : \r\n" + err.Message);
    }
}

我不明白的奇怪的事情是名为 currentIndex 的变量如何成为 >=executions 变量,因为只有循环操纵这两个变量并且应该强制执行相反的操作。 所以我认为我对并行处理如何发生在这里的理解中遗漏了一些东西。

c# parallel-processing buffer-overflow
1个回答
1
投票

捕获循环变量有一个众所周知的问题。 所以你应该写

for ( int index = 0; index < executions; index++) { int currentIndex = index; Action parallelAction = () => { ...

另一个可能的问题:

parameters[randoms[currentIndex] % parametersCount];

据您所知,
randoms

中的值可能全部为零。您确定不想创建一个 0..executions 数组,然后

shuffle
来代替吗? 但是我看不出这个例子失败的任何明显原因。但是如果您进行一些调试,索引等错误应该相当明显。

© www.soinside.com 2019 - 2024. All rights reserved.