简体   繁体   中英

Passing instance property to static method in Async Tasks

The code bellow:

namespace ConsoleApp2
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    class Program
    {
        static async Task Main(string[] args)
        {
            var split = new SplitService();

            var tasks = new List<Task>();
            for (var nI = 0; nI < 10; nI++)
            {
                var fathers = new List<Father> { new Father { Id = Guid.NewGuid() } };

                var task = new Task (() => split.Split(fathers));
                tasks.Add(task);
            };

            foreach (var task in tasks)
            {
                task.Start();
            }

            Console.ReadKey();
        }
    }

    public class SplitService
    {
        public IEnumerable<Father> Split(List<Father> fathers)
        {
            this.FatherProperties = fathers.GetFatherValues();

            this.RecalculateProperties(fathers);

            return fathers;
        }

        public List<FatherProperties> FatherProperties { get; private set; } = new List<FatherProperties>();

        public void RecalculateProperties(List<Father> fathers)
        {
            fathers.Update(this.FatherProperties);
        }
    }

    public static class FatherExtensions
    {
        public static List<FatherProperties> GetFatherValues(this List<Father> fathers)
        {
            return new List<FatherProperties>
            {
                new FatherProperties
                {
                    FatherId = fathers.FirstOrDefault().Id
                }
            };
        }

        public static void Update(this List<Father> fathers, List<FatherProperties> properties)
        {
            foreach (var father in fathers)
            {
                var match =
                    ( 
                     from value in properties
                     where value.FatherId == father.Id
                     select new
                     {
                         father.Id
                     }).SingleOrDefault();

                if (match == null)
                {
                    Console.WriteLine("Error");
                }
                else
                {
                    Console.WriteLine(match.Id); 
                }
            }
        }
    }

    public class Father
    {
        public Guid Id { get; set; }
    }

    public class FatherProperties
    {
        public Guid FatherId { get; set; }
    }
}

Gives errors is more than one thread is running. Can anyone help me with the reason why? Is this line:

fathers.Update(this.FatherProperties);

changes to this:

fathers.Update(father.GetFatherValues());

The code works.

Is this related to the access of the property? I can't figure out why. I tried to read many websites but still can't find the reason of this error.

Thanks for the help.

You are using the same instance of SplitService for all your tasks. Inside you are modifying it's member FatherProperties .

Obviously, that's why you have this behavior.

Create a service for each task:

for (var nI = 0; nI < 10; nI++)
{
    var split = new SplitService(); // <-- a dedicated service for each

    var fathers = new List<Father> { new Father { Id = Guid.NewGuid() } };
    var task = new Task (() => split.Split(fathers));
    tasks.Add(task);
};

First: Your excessive use of extension methods make the code very hard to read.
Second: You are pulling away the very collection you are using th compare. You use only ONE SplitService and its FatherProperties and you are changeing them in every call to split.Split(fathers). Since you are doing it multithreaded, you compare in one thread while another just puts a new fatherproperties collection in there. When using the GetFatherValues() again you are avoiding this behavior and therefore not getting an error.

Put the creation of the splitservice into the iteration.

static void Main(string[] args)
    {
        var tasks = new List<Task>();
        for (var nI = 0; nI < 100; nI++)
        {
            var fathers = new List<Father> { new Father { Id = Guid.NewGuid() } };
            var split = new SplitService();
            var task = new Task(() => split.Split(fathers));
            tasks.Add(task);
        };

        foreach (var task in tasks)
        {
            task.Start();
        }

        Console.ReadKey();
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM