CountdownEvent不等待所有线程发出信号

时间:2014-06-21 16:24:42

标签: c# multithreading countdownevent

我有以下多线程代码来计算Euler的数字。我是多线程编程的新手,也许我错过了一些东西。由于某种原因,countdown.Wait()不等待所有线程,而且totalSum几乎每次都不同。看起来它会跳过一些中间数。

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;
    }
}

2 个答案:

答案 0 :(得分:0)

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

    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,

答案 1 :(得分: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;
    }
}

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