For Loop result in Overflow with Task.Run or Task.Start

后端 未结 2 1480
孤独总比滥情好
孤独总比滥情好 2020-12-16 16:53

got a Problem, hope someone can help me out.

i try to start 4 Task in an Loop but im getting an ArgumentOutOfRangeException:

 for (int i = 0; i <          


        
相关标签:
2条回答
  • 2020-12-16 17:36

    In C# 5, the loop variable of a foreach will be logically inside the loop, and therefore closures will close over a fresh copy of the variable each time. The "for" loop will not be changed.

    Another way is that:

    1. Create tasks
    2. Run the tasks.
    3. Wait all task to finish.

    The demo code as follow:

     internal class Program
    {
        private static void Main(string[] args)
        {
            Task[] tasks = new Task[4];
    
            for (int i = 0; i < 4; i++)
            {
                //start task with current connection
                tasks[i] = new Task<byte[]>(GetData,i);
            }
    
            foreach (var task in tasks)
            {
                task.Start();
            }
    
            Task.WaitAll(tasks);
    
            Console.Read();
        }
    
        private static byte[] GetData(object index)
        {
            var i = (int) index;
            switch (i)
            {
                case 0:
    
                    //return plc.ReadBytes(DataType.DataBlock, 50, 0, 200);
                    Console.WriteLine(i);
                    return new byte[] { };
                case 1:
                //return plc.ReadBytes(DataType.DataBlock, 50, 200, 200);
                case 2:
                    Console.WriteLine(i);
                    return new byte[] { };
                //return plc.ReadBytes(DataType.DataBlock, 50, 500, 200);
                case 3:
                    Console.WriteLine(i);
                    return new byte[] { };
                //return plc.ReadBytes(DataType.DataBlock, 50, 700, 200);
                case 4:
                    //return plc.ReadBytes(DataType.DataBlock, 50, 900, 117);
                    Console.WriteLine(i);
                    return new byte[] { };
    
                default:
                    return null;
            }
        }
    }
    

    OUTPUT:

        3  
        1  
        0  
        2  
    

    Note: it's new Task<byte[]>(GetData,i); not new Task<byte[]>(()=>GetData(i));

    ()=>v means "return the current value of variable v", not "return the value v was back when the delegate was created". Closures close over variables, not over values.

    So the new Task<byte[]>(GetData,i); have no " Closures Problem "

    0 讨论(0)
  • 2020-12-16 17:41

    It's probably caused by a closure problem.

    Try this:

     for (int i = 0; i < 4; i++)
     {
          //start task with current connection
          int index = i;
          tasks[index] = Task<byte[]>.Run(() => GetData(index, plcPool[index]));
     }
    

    What is probably happening is that when the last thread starts running, the loop has already incremented i to 4, and that's the value that gets passed to GetData(). Capturing the value of i into a separate variable index and using that instead should solve that issue.

    As an example, if you try this code:

    public static void Main()
    {
        Console.WriteLine("Starting.");
    
        for (int i = 0; i < 4; ++i)
            Task.Run(() => Console.WriteLine(i));
    
        Console.WriteLine("Finished. Press <ENTER> to exit.");
        Console.ReadLine();
    }
    

    it will often give you this kind of output:

    Starting.
    Finished. Press <ENTER> to exit.
    4
    4
    4
    4
    

    Change that code to:

    public static void Main()
    {
        Console.WriteLine("Starting.");
    
        for (int i = 0; i < 4; ++i)
        {
            int j = i;
            Task.Run(() => Console.WriteLine(j));
        }
    
        Console.WriteLine("Finished. Press <ENTER> to exit.");
        Console.ReadLine();
    }
    

    and you get something like

    Starting.
    Finished. Press <ENTER> to exit.
    0
    1
    3
    2
    

    Note how it is STILL NOT NECESSARILY IN ORDER! You will see all the correct values printed out, but in an indeterminate order. Multithreading is tricksy!

    0 讨论(0)
提交回复
热议问题