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

本文关键字:信号 线程 等待 CountdownEvent | 更新日期: 2023-09-27 18:09:46

我有以下多线程代码计算欧拉数。我是新的多线程编程,也许我错过了一些东西。由于某些原因,count . 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;
    }
}

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

@usr提出了一个很好的观点:您最好使用ConcurrentStack<T>ConcurrentQueue<T>,详见http://msdn.microsoft.com/en-us/library/system.collections.concurrent%28v=vs.110%29.aspx。此外,最好使用Task实现算法。工厂由Alexandra Rusina在http://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()));
                  });
        }
    }

希望这将帮助。祝好,

您错误地使用了countdowevent。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;
    }
}

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