简体   繁体   中英

Thread synchronizing using Tasks and Parallel APIs

I am pasting 4 code snippets, where Parallelization is attempted using the following APIs:

Parallel.ForEach
Parallel.Invoke
Task.Run
Task.Factory.StartNew

Problem attempts to parallelize such that there are two for loops, inner and outer and for each execution of the outer loop everything in the inner loop should be executed in the Parallel.

I am able to get it working using Parallel.ForEach and all the others lead to exception as for the Inner counter, that value exceeds the array index, when in my view it should not be the case. Also index miss the target by one higher value, for example, when the size of the index is 500, it tries to access value 500, when ideally it should stop at 499. Am I missing something. Following are the code snippets, please have a look:

Parallel.ForEach (Working)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{    
    class Elements
    {
        public int innerValue;
        public int outerValue;

        public Elements(int innerValue, int outerValue)
        {
            this.innerValue = innerValue;
            this.outerValue = outerValue;
        }
    }

    class Program
    {
        private static int threadingCounter = 0;
        private static int innerCounter = 500;
        private static int outerCounter = 1000;
        private static int[,] inOut;
        private static int hitCount = 0;
        private static int exceptionCount = 0;
        private static List<int> innerCount = new List<int>();



        static void Main(string[] args)
        {
            inOut = new int[innerCounter, outerCounter];
            Program myProgram = new Program();

            for (int iCount = 0; iCount < innerCounter; iCount++)
                innerCount.Add(iCount);

            try
            {
                for (int outer = 0; outer < outerCounter; outer++)
                {
                    Parallel.ForEach<int>(innerCount, inner =>
                    {
                        myProgram.ThreadCall(new Elements(inner,outer));
                    }
                    );

                    Console.WriteLine("Main Thread Released Post Wait ...");
                    Console.WriteLine("Hit Count :: " + hitCount);
                    Console.WriteLine("Exception Count :: " + exceptionCount);

                    if (threadingCounter != 0)
                        Console.WriteLine("Threading Counter post Inner Loop :: " + threadingCounter);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: " + ex.Message);
            }
            finally
            {                
                if (innerCount != null)
                    innerCount = null;

            }
        }


        public void ThreadCall(object state)
        {
            try
            {
                Interlocked.Increment(ref hitCount);

                Elements localElement = (Elements)state;
                int localInner = localElement.innerValue;
                int localOuter = localElement.outerValue;
                int finalValue = inOut[localInner, localOuter];
            }
            catch (Exception ex)
            {               
                Console.WriteLine("Exception :: " + ex.Message);
            }
        }
    }
}

Parallel.Invoke (Failing with array out of Index value, tries to fetch inner index - 500)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{
    /// <summary>
    /// 
    /// </summary>
    class Elements
    {
        public int innerValue;
        public int outerValue;

        public Elements(int innerValue, int outerValue)
        {
            this.innerValue = innerValue;
            this.outerValue = outerValue;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    class Program
    {
        private static int innerCounter = 500;
        private static int outerCounter = 1000;
        private static int[,] inOut;
        private static int hitCount = 0;
        private static int exceptionCount = 0;

        private static List<Action> alSync = new List<Action>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            inOut = new int[innerCounter, outerCounter];
            Program myProgram = new Program();

            try
            {
                for (int outer = 0; outer < outerCounter; outer++)
                {

                    for (int inner = 0; inner < innerCounter; inner++)
                        alSync.Add(() => myProgram.ThreadCall(new Elements(inner, outer)));

                    Parallel.Invoke(alSync.ToArray());                            
                    alSync.Clear();

                    Console.WriteLine("Main Thread Released Post Wait ...");
                    Console.WriteLine("Hit Count :: " + hitCount);
                    Console.WriteLine("Exception Count :: " + exceptionCount);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: " + ex.Message);
            }
            finally
            {
                if (alSync != null)
                    alSync = null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        public void ThreadCall(object state)
        {
            try
            {
                Interlocked.Increment(ref hitCount);
                Elements localElement = (Elements)state;
                int localInner = localElement.innerValue;
                int localOuter = localElement.outerValue;
                int finalValue = inOut[localInner, localOuter];
            }
            catch (Exception ex)
            {
                Interlocked.Increment(ref exceptionCount);
                Console.WriteLine("Exception :: " + ex.Message);
            }

        }
    }
}

Task.Run (Failing with array out of Index value, tries to fetch inner index - 500)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{
    /// <summary>
    /// 
    /// </summary>
    class Elements
    {
        public int innerValue;
        public int outerValue;

        public Elements(int innerValue, int outerValue)
        {
            this.innerValue = innerValue;
            this.outerValue = outerValue;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    class Program
    {
        private static int innerCounter = 500;
        private static int outerCounter = 1000;
        private static int[,] inOut;
        private static int hitCount = 0;
        private static int exceptionCount = 0;

        private static List<Task> tlSync = new List<Task>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            inOut = new int[innerCounter, outerCounter];
            Program myProgram = new Program();

            try
            {
                for (int outer = 0; outer < outerCounter; outer++)
                {                  

                    for (int inner = 0; inner < innerCounter; inner++)
                        tlSync.Add(Task.Run(() => myProgram.ThreadCall(new Elements(inner, outer))));

                    Task.WaitAll(tlSync.ToArray());
                    tlSync.Clear();

                    Console.WriteLine("Main Thread Released Post Wait ...");
                    Console.WriteLine("Hit Count :: " + hitCount);
                    Console.WriteLine("Exception Count :: " + exceptionCount);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: " + ex.Message);
            }
            finally
            {               
                if (tlSync != null)
                    tlSync = null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        public void ThreadCall(object state)
        {
            try
            {
                Interlocked.Increment(ref hitCount);
                Elements localElement = (Elements)state;
                int localInner = localElement.innerValue;
                int localOuter = localElement.outerValue;
                int finalValue = inOut[localInner, localOuter];
            }
            catch (Exception ex)
            {
                Interlocked.Increment(ref exceptionCount);
                Console.WriteLine("Exception :: " + ex.Message);
            }           

        }
    }
}

Task.Factory.StartNew (Failing with array out of Index value, tries to fetch inner index - 500)

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace TestThreads
{
    /// <summary>
    /// 
    /// </summary>
    class Elements
    {
        public int innerValue;
        public int outerValue;

        public Elements(int innerValue, int outerValue)
        {
            this.innerValue = innerValue;
            this.outerValue = outerValue;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    class Program
    {
        private static int innerCounter = 500;
        private static int outerCounter = 1000;
        private static int[,] inOut;
        private static int hitCount = 0;
        private static int exceptionCount = 0;

        private static List<Task> tlSync = new List<Task>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            inOut = new int[innerCounter, outerCounter];
            Program myProgram = new Program();

            try
            {
                for (int outer = 0; outer < outerCounter; outer++)
                {

                    for (int inner = 0; inner < innerCounter; inner++)
                        tlSync.Add(Task.Factory.StartNew(() =>  
myProgram.ThreadCall(new Elements(inner, outer))));

                    Task.WaitAll(tlSync.ToArray());
                    tlSync.Clear();

                    Console.WriteLine("Main Thread Released Post Wait ...");
                    Console.WriteLine("Hit Count :: " + hitCount);
                    Console.WriteLine("Exception Count :: " + exceptionCount);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: " + ex.Message);
            }
            finally
            {
                if (tlSync != null)
                    tlSync = null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="state"></param>
        public void ThreadCall(object state)
        {
            try
            {
                Interlocked.Increment(ref hitCount);
                Elements localElement = (Elements)state;
                int localInner = localElement.innerValue;
                int localOuter = localElement.outerValue;
                int finalValue = inOut[localInner, localOuter];
            }
            catch (Exception ex)
            {
                Interlocked.Increment(ref exceptionCount);
                Console.WriteLine("Exception :: " + ex.Message);
            }

        }
    }
}

Not sure what the use of tlSync is i don't see why you would want to push the tasks to a generic list.

If you want to do some stuff and update the ui you can maybe inspire from this function i used for a forms program i once wrote

var ui = TaskScheduler.FromCurrentSynchronizationContext();
someList
    .ForEach(f => Task.Factory.StartNew(() =>
    {
        // do stuff
    })
    .ContinueWith(task =>
    {
        if (task.IsCompleted)
        {
            // update UI
            // called after each task above completes
        }
    }, ui));

Or you might have a closure problem with inner/outer, and you could try changing this code

for (int inner = 0; inner < innerCounter; inner++)
    tlSync.Add(Task.Factory.StartNew(() => myProgram.ThreadCall(new Elements(inner, outer))));

To this

for (int inner = 0; inner < innerCounter; inner++) {
    var nInner = inner;
    var nOuter = outer;
    tlSync.Add(Task.Factory.StartNew(() => myProgram.ThreadCall(new Elements(nInner, nOuter))));    
}

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