Engr Rslan
Engr Rslan

Reputation: 129

Parallel Tasks Calling Static function

I Have issue with parllel Tasks My Code

namespace ITDevices  
{  
    using System.Linq;  
    using System.Collections.Generic;  
    using System.Threading.Tasks;  
    using System;

    /*Device Modal*/
    public class Device
    {
        public string IP { get; set; }
        public string Name { get; set; }
        public string MAC { get; set; }
    }

    /*Entry Class*/
    class Program
    {
        static async void Main(string[] args)
        {
            List<Task<Device>> Tasks = new List<Task<Device>>();

            for(int i=2;i==0;i--)
            {
                Tasks.Add(Task.Factory.StartNew<Device>(
                    ()=> {
                            Device free = Helper.GetFreeDevice();
                            return free;
                        }
                    ));       
            }
            await Task.WhenAll(Tasks.ToArray());
            foreach(Task<Device> item in Tasks)
            {
                Console.WriteLine(item.Result.IP);
            }
            Console.ReadLine();
        }
    }
    /*Devices Helper*/
    static class Helper
    {


        public static List<Device> UsedDevices = new List<Device>();

        public static Device GetFreeDevice()
        {
             List<Device> OnlineDevices = new List<Device>()
            {
                new Device { IP="192.168.1.15",Name="PerryLabtop",MAC="AC:DS:F2:CC:2D:7A"},
                new Device { IP="192.168.1.20",Name="MAYA-PC",MAC="7D:E9:2C:FF:E7:2D"},
                new Device { IP="192.168.1.2",Name="server",MAC="D8:C2:A4:DC:E5:3A"}
            };

            Device FreeDevice = OnlineDevices.Where(x => !UsedDevices.Contains(x)).SingleOrDefault();
            if (FreeDevice != null)
                UsedDevices.Add(FreeDevice);
            return FreeDevice;
        }
    }
}

//Output   
//192.168.1.15  
//192.168.1.15

But expected output must be
//192.168.1.15
//192.168.1.20

When debugging the project

all tasks execute GetFreeDevice() function at same time line by line I need to make tasks wait while current GetFreeDevice() function execution done .. or any thing helpful

THANKS ALL

Upvotes: 3

Views: 1427

Answers (2)

Cologler
Cologler

Reputation: 724

try:

public static Device GetFreeDevice()
    {
         List<Device> OnlineDevices = new List<Device>()
        {
            new Device { IP="192.168.1.15",Name="PerryLabtop",MAC="AC:DS:F2:CC:2D:7A"},
            new Device { IP="192.168.1.20",Name="MAYA-PC",MAC="7D:E9:2C:FF:E7:2D"},
            new Device { IP="192.168.1.2",Name="server",MAC="D8:C2:A4:DC:E5:3A"}
        };

        Device FreeDevice = OnlineDevices.Where(x => !UsedDevices.Contains(x)).SingleOrDefault();
        if (FreeDevice != null)
            lock (UsedDevices)
                UsedDevices.Add(FreeDevice);
        return FreeDevice;
    }

------------------------ UPDATE

try:

public static Device GetFreeDevice()
    {
         List<Device> OnlineDevices = new List<Device>()
        {
            new Device { IP="192.168.1.15",Name="PerryLabtop",MAC="AC:DS:F2:CC:2D:7A"},
            new Device { IP="192.168.1.20",Name="MAYA-PC",MAC="7D:E9:2C:FF:E7:2D"},
            new Device { IP="192.168.1.2",Name="server",MAC="D8:C2:A4:DC:E5:3A"}
        };

        lock (UsedDevices)
        {
            Device FreeDevice = OnlineDevices.Where(x => !UsedDevices.Contains(x)).SingleOrDefault();
            if (FreeDevice != null)
                UsedDevices.Add(FreeDevice);
        }
        return FreeDevice;
    }

Upvotes: 0

Ňuf
Ňuf

Reputation: 6207

Several problems must be solved to make it work properly:

  1. You probably reversed condition in for loop, because int i = 2; i == 0; i-- will do nothing. Replace i == 0 with i != 0

  2. async Main method doesn't make sense (see for example this blog) and actually doesn't even compile in Visual Studio. To fix this, you can for example wait for tasks to complete synchronously (use .Wait() instead of await)

  3. To prevent multiple threads to run GetFreeDevice() method simultaneously, simply place lock around code that uses shared objects - which is whole method body in your case.

  4. Because you create new list of OnlineDevices each time GetFreeDevice() method is called, UsedDevices.Contains(x) will not work as expected. By default, objects are compared by their reference. So .Contains(x) will compare Device objects in UsedDevices list (which were put there in one of previous calls) with newly created Device objects, which will never be equal (references of these object will be different despite IP, Name and MAC being the same). To fix this, you could either override Equals() and GetHashCode() methods on Device class, or (as i did) create just one static list of Device objects.

  5. You must replace SingleOrDefault() with FirstOrDefault(). With SingleOrDefault(), program would throw exception if there is more than one unused device, while FirstOrDefault() will take first unused device even if there is more than one.

Full source code with all proposed fixes:

namespace ITDevices
{
    /*Device Modal*/
    public class Device
    {
        public string IP { get; set; }
        public string Name { get; set; }
        public string MAC { get; set; }
    }

    /*Entry Class*/
    class Program
    {
        static void Main(string[] args)
        {
            List<Task<Device>> Tasks = new List<Task<Device>>();

            for (int i = 2; i != 0; i--)
            {
                Tasks.Add(Task.Factory.StartNew<Device>(
                    () => {
                        Device free = Helper.GetFreeDevice();
                        return free;
                    }
                    ));
            }
            Task.WhenAll(Tasks.ToArray()).Wait();
            foreach (Task<Device> item in Tasks)
            {
                Console.WriteLine(item.Result.IP);
            }
            Console.ReadLine();
        }
    }
    /*Devices Helper*/
    static class Helper
    {
        public static List<Device> UsedDevices = new List<Device>();

        static List<Device> OnlineDevices = new List<Device>()
        {
            new Device { IP="192.168.1.15",Name="PerryLabtop",MAC="AC:DS:F2:CC:2D:7A"},
            new Device { IP="192.168.1.20",Name="MAYA-PC",MAC="7D:E9:2C:FF:E7:2D"},
            new Device { IP="192.168.1.2",Name="server",MAC="D8:C2:A4:DC:E5:3A"}
        };

        static Object LockObject = new Object();

        public static Device GetFreeDevice()
        {
            lock (LockObject)
            {
                Device FreeDevice = OnlineDevices.Where(x => !UsedDevices.Contains(x)).FirstOrDefault();
                if (FreeDevice != null)
                    UsedDevices.Add(FreeDevice);
                return FreeDevice;
            }
        }
    }
}

Upvotes: 4

Related Questions