Я невероятно новичок в C#, но цель этого проекта состояла в том, чтобы генератор простых чисел использовал блокировку потоков и использовал несколько процессорных ядер. Я думал, что получаю зависание C#, но у меня есть несколько проблем.C# SpinLock и Threading. StackOverflowException и Exited с кодом 259 (0x103)
Запуск в Visual Studio дает кучу: Выход с кодом 259 (0x103) сообщений. Я читал, что это ошибка с Visual Studio и на самом деле не проблема?
Ядром проблемы является исключение StackOverflowException. Я знаком с концепцией переполнения стека, но мне трудно определить, где оно происходит. Я могу догадаться, что это как-то связано с заполнением моих очередей.
Программа выложена следующим образом:
Calculator.cs: Чтение чисел из сгенерированного файла, помещает их в очередь, начинает резьб на этих очередях
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace PrimeProject{
internal class Calculator {
public void Run(NumberReader reader) {
var results = new List<long>();
var numbersToCheck = new Queue<long>();
StartComputationThreads(results, numbersToCheck);
var progressMonitor = new ProgressMonitor(results);
new Thread(progressMonitor.Run) {IsBackground = true}.Start();
var someList = new List<long>();
foreach (var value in reader.ReadIntegers())
{
someList.Add(value);
if (someList.Count == 1000)
{
numbersToCheck.EnqueueCollection(someList);
someList.Clear();
}
}
if (someList.Count > 0)
{
numbersToCheck.EnqueueCollection(someList);
someList.Clear();
}
while (numbersToCheck.Count() > 0)
{
Thread.Sleep(100); // wait for the computation to complete.
}
Console.WriteLine("{0} of the numbers were prime", progressMonitor.TotalCount);
}
private static void StartComputationThreads(List<long> results, Queue<long> numbersToCheck)
{
var threads = CreateThreads(results, numbersToCheck);
threads.ForEach(thread => thread.Start());
}
private static List<Thread> CreateThreads(List<long> results, Queue<long> numbersToCheck)
{
var threadCount = Environment.ProcessorCount*2;
Console.WriteLine("Using {0} compute threads and 1 I/O thread", threadCount);
var threads =
(from threadNumber in Sequence.Create(0, threadCount)
let calculator = new IsNumberPrimeCalculator(results, numbersToCheck)
let newThread =
new Thread(calculator.CheckIfNumbersArePrime) {
IsBackground = true,
Priority = ThreadPriority.BelowNormal
}
select newThread).ToList();
return threads;
}
}
}
Semaphore.cs: Пользовательские очереди класса, создает семафоры, вызовы SpinLock. Обновлено с bool lockTaken перед тем, как попробовать {}.
using System;
using System.Collections.Generic;
using System.Threading;
internal sealed class Queue<T>
{
private readonly Semaphore semaphoreOne;
private readonly Semaphore semaphoreTwo;
private readonly SpinLock _spinLock;
private readonly Queue<T> listQueue;
public Queue()
{
this.semaphoreOne = new Semaphore(0x3e8, 0x3e8);
this.semaphoreTwo = new Semaphore(0, 0x3e8);
this._spinLock = new SpinLock();
this.listQueue = new Queue<T>();
}
public int Count()
{
int count;
bool lockTaken = false;
try
{
this._spinLock.Enter(ref lockTaken);
count = this.listQueue.Count();
}
finally
{
this._spinLock.Exit();
}
return count;
}
public void EnqueueCollection(IReadOnlyCollection<long> collection)
{
for (int i = 0; i < collection.Count; i++)
{
this.semaphoreOne.WaitOne();
}
bool lockTaken = false;
try
{
this._spinLock.Enter(ref lockTaken);
foreach (long local in collection)
{
this.listQueue.Enqueue(local);
}
}
finally
{
this._spinLock.Exit(true);
}
this.semaphoreTwo.Release(collection.Count);
}
public void Enqueue(long num)
{
this.semaphoreOne.WaitOne();
bool lockTaken = false;
try
{
this._spinLock.Enter(ref lockTaken);
this.listQueue.Enqueue(num);
}
finally
{
this._spinLock.Exit();
}
this.semaphoreTwo.Release(1);
}
public long Dequeue()
{
long local;
this.semaphoreTwo.WaitOne();
bool lockTaken = false;
try
{
this._spinLock.Enter(ref lockTaken);
local = this.listQueue.Dequeue();
}
finally
{
this._spinLock.Exit();
}
this.semaphoreOne.Release();
return local;
}
}
SpinLock.cs: Удален из-за изменения в Semaphore.cs
других классы (для справки) включают в себя: isNumberPrime, ProgressMonitor, читатель, и писатель.
Первоначально я назвал его по-разному, но это вызвало проблемы в Semaphore.cs всякий раз, когда я называю «this._spinLock.Enter()», для этого требуется ref bool. Должен ли я положить bool lockTaken и while loop и поместить его в мой класс Семафор? –
Я только что обновил код выше. Я думаю, положив bool lockTaken в разделе try {}, мне больше не нужен мой класс SpinLock? Хотя я все еще получаю ошибки переполнения стека. –
@JoeLaMagReiter Да, ваш класс spinlock не добавляет значения и, следовательно, может быть удален. В какой момент вы получаете stackoverflow? Вы полностью удалили класс 'SpinLock'? –