0

I've got the following multithreaded code for calculating Euler's number. I'm new in multithreaded programming and maybe I'm missing something. For some reason countdown.Wait() is not waiting for all the threads and totalSum is different almost every time. It looks like it skips some of the intermediate sums.

public static class Program
{
    private static int elementsCount = 500;
    private static int threadsCount = 20;
    private static string outputFileName = "defaultFileName.txt";
    private static bool isInQuietMode = false;

    private static BigRational totalSum = new BigRational(0.0m);

    private static CountdownEvent countDown = new CountdownEvent(threadsCount);
    private static Object locker = new Object();

    private static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateEulerNumber), threadIndex);
        }

        countDown.Wait();

        File.WriteAllText(outputFileName, "Euler's number: " + totalSum);

        stopwatch.Stop();

        Console.WriteLine("Result: ");
        Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
        if (!isInQuietMode)
        {
            Console.WriteLine("Euler's number - " + totalSum);
        }
    }

    private static void CalculateEulerNumber(object threadIndexObject)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        int threadIndex = Convert.ToInt32(threadIndexObject);

        BigRational sum = new BigRational(0.0m);

        for (int k = threadIndex; k < elementsCount; k += threadsCount)
        {
            BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
            BigRational denominator = Factorial(3 * k);

            sum += BigRational.Divide(numerator, denominator);
        }

        totalSum = BigRational.Add(totalSum, sum);

        stopwatch.Stop();

        lock (locker)
        {
            int threadNumber = threadIndex + 1;

            Console.WriteLine("Тhread " + threadNumber + ": ");
            Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);

            if (!isInQuietMode)
            {
                Console.WriteLine("Intermediate sum - " + sum.ToDecimalString(40));
            }

            Console.WriteLine();
        }

        countDown.Signal();
    }

    private static BigRational Factorial(int n)
    {
        BigRational factorial = 1;

        for (int i = 1; i <= n; i++)
        {
            factorial *= i;
        }

        return factorial;
    }
}
4

2 回答 2

0

@usr 提出了一个很好的观点:您最好使用ConcurrentStack<T>ConcurrentQueue<T>http://msdn.microsoft.com/en-us/library/system.collections.concurrent%28v=vs.110%29.aspx中详细说明。此外,最好使用 Task.Factory 来实现您的算法,正如Alexandra Rusinahttp://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-中所解释的那样4-getting-started.aspx。根据提到的资源,您的解决方案可能如下所示(给您大致的想法)

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

ConcurrentStack<int> cs = new ConcurrentStack<int>();

        public static double YourFunction(int SomeNumber)
        {
            // computation of result
            return result;
        }

        private void start_Click(object sender, RoutedEventArgs e)
        {
            textBlock1.Text = "";
            label1.Content = "Milliseconds: ";

            var watch = Stopwatch.StartNew();
            List<Task> tasks = new List<Task>();
            for (int i = 2; i < 20; i++)
            {
                int j = i;
                var t = Task.Factory.StartNew(() =>
                {
                    int result = YourFunctiopn(j);
                    this.Dispatcher.BeginInvoke(new Action(() =>
                         cs.Add(result ))
                    , null);
                });
                tasks.Add(t);
            }

            Task.Factory.ContinueWhenAll(tasks.ToArray(),
                  result =>
                  {
                      var time = watch.ElapsedMilliseconds;
                      this.Dispatcher.BeginInvoke(new Action(() =>
                          label1.Content += time.ToString()));
                  });

        }
    }

希望这会有所帮助。Rgds,

于 2014-06-21T16:48:41.007 回答
0

您错误地使用了 CountDownEvent。CountDownEvent 用于发出信号,您在当前程序中不需要它。您可以使用以下任务执行此操作:

 public class Class1
{
    private static int elementsCount = 500;
    private static int threadsCount = 20;
    private static string outputFileName = "defaultFileName.txt";
    private static bool isInQuietMode = false;
    private static BigRational totalSum = new BigRational(0.0m);

    public static void Main1(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        List<Task<BigRational>> tasks = new List<Task<BigRational>>();

        //Create the tasks
        for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
        {
            Task<BigRational> task = new Task<BigRational>((data)=>
            {
                return CalculateEulerNumber(data);

            },threadIndex);
            tasks.Add(task);
        }
        foreach (var task in tasks)
        {
            task.Start();
        }
        //Wait for tasks
        Task.WaitAll(tasks.ToArray());

        //Add the results
        foreach (var task in tasks)
        {
            totalSum = BigRational.Add(totalSum, task.Result); 
        }
        File.WriteAllText(outputFileName, "Euler's number: " + totalSum);

        stopwatch.Stop();

        Console.WriteLine("Result: ");
        Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
        if (!isInQuietMode)
        {
            Console.WriteLine("Euler's number - " + totalSum);
        }
    }

    private static BigRational CalculateEulerNumber(object threadIndexObject)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        int threadIndex = Convert.ToInt32(threadIndexObject);

        BigRational sum = new BigRational(0.0m);

        for (int k = threadIndex; k < elementsCount; k += threadsCount)
        {
            BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
            BigRational denominator = Factorial(3 * k);

           sum += BigRational.Divide(numerator, denominator);
        }
        stopwatch.Stop();
         int threadNumber = threadIndex + 1;

           Console.WriteLine("Тhread " + threadNumber + ": ");
           Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);

            if (!isInQuietMode)
            {
                Console.WriteLine("Intermediate sum - " + sum.ToString());
            }

           Console.WriteLine();
        return sum;
    }

    private static BigRational Factorial(int n)
    {
        BigRational factorial = 1;

        for (int i = 1; i <= n; i++)
        {
            factorial *= i;
        }

        return factorial;
    }
}

所以创建任务,每个任务可以单独运行并返回单独的总和。然后,您可以添加结果以创建总和。也不需要锁。

于 2014-06-21T17:16:16.627 回答