我试图在C#中使用Threads生成素数.用户必须输入要生成的线程数.运行代码时出现以下问题:
如果我尝试使用多个线程,有时会使Index超出范围异常.如果我再试一次,它会起作用.
每个线程都在计算相同的值.例如,如果我输入两个线程来生成2到100之间的素数(包括两者),我得到以下输出.
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
我已经完成了以下帖子.但我无法解决这些问题.我是线程概念的新手.如何解决这些问题?
简单的素数程序 - 线程C#的奇怪问题
这是我的代码
class Program { const int min = 2; const int max = 100; static Listprimes = new List (); static void GeneratePrimes (int start, int range) { bool isPrime = true; int end = start + range; for (int i = start; i <= end; i++) { for (int j = start; j <= end; j++) { if (i != j && i % j == 0) { isPrime = false; break; } } if (isPrime) { primes.Add (i); } isPrime = true; } } static void Main (string[] args) { int threadCount = Convert.ToInt32 (Console.ReadLine ()); Thread[] threads = new Thread[threadCount]; int range = (max - min) / threadCount; int start = min; for (int i = 0; i < threadCount; i++) { int startl = start; threads[i] = new Thread(new ThreadStart(() => GeneratePrimes(start, range))); startl += range; threads[i].Start (); } for (int i = 0; i < threadCount; i++) threads[i].Join(); PrintPrimes(); } static void PrintPrimes () { foreach (int i in primes) Console.WriteLine (i); } }
UPDATE
我根据NikolayKondratyev的回答提出了改变.但是当我使用更多线程时,我现在在列表中有重复的值(> 5)
第一个问题是你start
的线程错了.线程创建应该是
for (int i = 0; i < threadCount; i++) { var startl = start; threads[i] = new Thread(new ThreadStart(() => GeneratePrimes(startl, range))); start += range; threads[i].Start(); }
另外List
是不是线程安全的,insted的使用线程安全集合.例如ConcurrentQueue
及其方法Enqueue
.
for
条件也有问题,应该如下
for (var i = start; i < end; i++) { for (var j = min; j < end; j++) { ... } }
你可以用它来优化它
for (var j = min; j < Math.Sqrt(end); j++)
另一个问题是你有错误的范围,可能有未处理的值,因为例如start + range
小于max
5个线程.因此,对于最后一个线程,我们需要添加(max - min)%threadCount
更多值.这是完整的代码
class Program { private const int min = 2; private const int max = 100; private static readonly ConcurrentQueueprimes = new ConcurrentQueue (); private static void GeneratePrimes(int start, int range) { var isPrime = true; var end = start + range; for (var i = start; i < end; i++) { for (var j = min; j < Math.Sqrt(end); j++) { if (i != j && i%j == 0) { isPrime = false; break; } } if (isPrime) { primes.Enqueue(i); } isPrime = true; } } private static void Main(string[] args) { var threadCount = Convert.ToInt32(Console.ReadLine()); var threads = new Thread[threadCount]; var range = (max - min)/threadCount; var start = min; for (var i = 0; i < threadCount - 1; i++) { var startl = start; threads[i] = new Thread(() => GeneratePrimes(startl, range)); start += range; threads[i].Start(); } threads[threadCount - 1] = new Thread(() => GeneratePrimes(start, range + (max - min)%threadCount)); threads[threadCount - 1].Start(); for (var i = 0; i < threadCount; i++) threads[i].Join(); PrintPrimes(); } private static void PrintPrimes() { foreach (var i in primes) Console.WriteLine(i); } }