2014-10-11 7 views
0

Я невероятно новичок в 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, читатель, и писатель.

ответ

1

SpinLock Вашего класса, кажется, имеет свой собственный экземпляр, не уверен, что ваши намерения, но это приводит к бесконечному созданию SpinLock экземпляра, который использует всю память стека и, таким образом, приводит к StackoverflowException.

Я предлагаю вам дать другое название для вашего класса, так как SpinLock уже принят BCL.

+0

Первоначально я назвал его по-разному, но это вызвало проблемы в Semaphore.cs всякий раз, когда я называю «this._spinLock.Enter()», для этого требуется ref bool. Должен ли я положить bool lockTaken и while loop и поместить его в мой класс Семафор? –

+0

Я только что обновил код выше. Я думаю, положив bool lockTaken в разделе try {}, мне больше не нужен мой класс SpinLock? Хотя я все еще получаю ошибки переполнения стека. –

+0

@JoeLaMagReiter Да, ваш класс spinlock не добавляет значения и, следовательно, может быть удален. В какой момент вы получаете stackoverflow? Вы полностью удалили класс 'SpinLock'? –