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;
}
}
@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;
}
}
创建任务,每个任务可以单独运行并返回单独的总和。然后,您可以添加结果以创建总和。也不需要锁