锁定释放BulkCollector和FatalExecutionEngineError异常

时间:2011-12-28 22:21:28

标签: c# multithreading locking

我正在开发一个无锁堆栈和队列数据结构,我可以在其中放置尽可能多的项目,并在一次调用中收集所有项目,我认为我的设计是可靠的,并且它按预期工作直到我开始回忆一个意外的异常,我认为这在纯C#环境中是不可能的:

托管调试助手'FatalExecutionEngineError'检测到问题附加信息:运行时遇到致命错误。错误的地址位于线程0x16f0处的0x6caf6ac7处。错误代码是0xc0000005。此错误可能是CLR中的错误,也可能是用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括COM-interop或PInvoke的用户封送错误,这可能会破坏堆栈。

我似乎无法找到方法,并且想知道是否有人可以指导我找出错误的原因:

这是stackbulkcollector的实现:

public class StackBulkCollector<T> : IBulkCollector<T>
{        
    class Node
    {
        public T value;
        private bool m_isSet;
        private Node m_prev;

        public Node(T data)
        {
            value = data;
        }

        public Node()
        {                
        }

        public Node Prev
        {
            set
            {
                m_prev = value;
                m_isSet = true;
            }

            get
            {
                if (!m_isSet)
                {
                    SpinWait s = new SpinWait();
                    while (!m_isSet)
                    {
                        s.SpinOnce();
                    }
                }

                return m_prev;
            }
        }
    }

    class Enumerable : IEnumerable<T>
    {
        private Node m_last;

        public Enumerable(Node last)
        {
            m_last = last;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return new Enumerator(m_last);
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new Enumerator(m_last);
        }
    }

    class Enumerator : IEnumerator<T>
    {
        private readonly Node m_last;
        private Node m_current;

        public Enumerator(Node last)
        {
            var node = new Node();
            m_current = m_last = node;
            node.Prev = last;
        }

        public T Current
        {
            get { return m_current.value; }
        }

        public void Dispose()
        {
        }

        object System.Collections.IEnumerator.Current
        {
            get { return this; }
        }

        public bool MoveNext()
        {
            if (m_current == null)
            {
                return false;
            }

            m_current = m_current.Prev;
            return m_current != null;
        }

        public void Reset()
        {
            m_current = m_last;
        }
    }

    private Node m_last;

    public void Add(T data)
    {
        var node = new Node(data);
        node.Prev = Interlocked.Exchange(ref m_last, node);
    }

    public IEnumerable<T> GetBulk()
    {
        var last = Interlocked.Exchange(ref m_last, null);
        return new Enumerable(last);
    }
}

这是我用来测试它的测试程序:

class Program
{
    public static readonly int UseThreads = 4;
    public static readonly TimeSpan Duration = new TimeSpan(0,0,0,3);

    public static long[] AddedItems = new long[UseThreads];

    static void Main(string[] args)
    {
        IBulkCollector<TestData> bulkCollector = new QueuedBulkCollector<TestData>();
        while (true)
        {
            using (var countdownEvent = new CountdownEvent(UseThreads + 1))
            {
                var results = new Dictionary<int, List<TestData>>();
                if (bulkCollector is QueuedBulkCollector<TestData>)
                {
                    bulkCollector = new StackBulkCollector<TestData>();
                    Console.WriteLine("Starting StackBulkCollector Test");
                }
                else
                {
                    bulkCollector = new StackBulkCollector<TestData>();
                    Console.WriteLine("Starting QueuedBulkCollector Test");
                }
                for (int i = 0; i < UseThreads; i++)
                {
                    results[i] = new List<TestData>();
                    Thread t = new Thread(PushTestData);
                    t.Start(new object[] {i, bulkCollector, countdownEvent});
                }

                var start = DateTime.Now;
                Thread readerThred = new Thread(() =>
                                                    {
                                                        while ((DateTime.Now - start) <
                                                               (Duration - new TimeSpan(0, 0, 0, 0, 100)))
                                                        {
                                                            foreach (var testData in bulkCollector.GetBulk())
                                                            {
                                                                results[testData.Id].Add(testData);
                                                            }
                                                            //Console.WriteLine("Doing Some Read {0}", currBulk.Count);
                                                            System.Threading.Thread.Sleep(10);
                                                        }
                                                        countdownEvent.Signal();
                                                    });
                readerThred.Start();
                countdownEvent.Wait();

                var lastBulk = bulkCollector.GetBulk().ToList();
                foreach (var testData in lastBulk)
                {
                    results[testData.Id].Add(testData);
                }

                Console.WriteLine("Doing Last Read {0}", lastBulk.Count);

                long[] value = new long[UseThreads];
                long totalCount = 0;
                int errorCount = 0;
                for (int i = 0; i < UseThreads; i++)
                {
                    value[i] = AddedItems[i];
                    totalCount += value[i];
                    Console.WriteLine("Thread {0} Push {1} Items", i, value[i]);
                    var verifyArray = results[i].OrderBy(p => p.Value).ToList();
                    if (verifyArray.Count != value[i])
                    {
                        Console.WriteLine("Not Working Count miss match");
                        errorCount++;
                    }
                    else
                    {
                        var expected = 0;
                        foreach (var testData in verifyArray)
                        {
                            if (expected != testData.Value)
                            {
                                Console.WriteLine("NotWorking");
                                errorCount++;
                            }
                            expected++;
                        }
                    }
                }
                Console.WriteLine("Done Total Push {0} with {1} errors.", totalCount.ToString("#,##0") , errorCount);
                if (errorCount != 0)
                {
                    Console.ReadKey();
                }
            }
        }
    }

    private static void PushTestData(object o)
    {
        object[] parms = o as object[];
        int id = (int)parms[0];
        IBulkCollector<TestData> bulkCollector = (IBulkCollector<TestData>)parms[1];
        CountdownEvent endEvetn = (CountdownEvent)parms[2];
        AddedItems[id] = 0;
        var start = DateTime.Now;
        while ((DateTime.Now - start) < Duration)
        {
            bulkCollector.Add(new TestData() { Id = id, Value = AddedItems[id]});
            AddedItems[id]++;
        }

        endEvetn.Signal();
    }
}

欢迎任何建议。

1 个答案:

答案 0 :(得分:1)

抱歉,有问题的内存模块是问题的原因,它已被替换,问题已解决。