【问题标题】:C# SpinLock and Threading. StackOverflowException and Exited with code 259 (0x103)C# SpinLock 和线程。 StackOverflowException 并以代码 259 (0x103) 退出
【发布时间】:2014-12-06 15:36:55
【问题描述】:

我对 C# 非常陌生,但这个项目的目标是让素数生成器使用线程锁定并使用多个处理核心。我以为我掌握了 C# 的窍门,但我遇到了一些问题。

在 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、reader 和 writer。

【问题讨论】:

    标签: c# multithreading stack-overflow spinlock


    【解决方案1】:

    您的SpinLock 类似乎有自己的实例,不确定您的意图是什么,但这会导致无限创建SpinLock 实例,该实例会利用所有堆栈内存,从而导致StackoverflowException

    我建议你为你的班级取一个不同的名字,因为SpinLock 已经被 BCL 占用了。

    【讨论】:

    • 我最初命名它的方式不同,但是每当我调用“this._spinLock.Enter()”时它都会在 Semaphore.cs 中引起问题,它需要 ref bool。我应该把 bool lockTaken 和 while 循环放在我的 Semaphore 类中吗?
    • 我刚刚更新了上面的代码。我认为通过将 bool lockTaken 放在 try{} 部分中,我实际上不再需要我的 SpinLock 类了吗?虽然我仍然遇到堆栈溢出错误。
    • @JoeLaMagReiter 是的,您的自旋锁类没有增加任何价值,因此可以删除。在什么时候你得到stackoverflow?您是否完全删除了 SpinLock 类?
    • 是的,SpinLock 类已从项目中删除。更新后的 Semaphore.cs 代码已在上面的帖子中更新。是的,仍然出现 stackoverflow 错误。
    • 所以,似乎在运行代码时,Visual Studio 只是弹出了一个指向this.semaphoreOne = new Semaphore(0x3e8, 0x3e8); 的框并说堆栈溢出。我尝试将这些更改为常规整数,但没有成功。我是否错误地处理了信号量?
    猜你喜欢
    • 2014-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多