首页 > 解决方案 > 从多个线程分配和获取对象引用是否需要同步代码?

问题描述

免责声明:此代码永远连续运行两个线程。运行风险自负。

using System;
using System.Threading.Tasks;

namespace ConsoleApp126
{
    internal class AnyClass
    {
        private int _state;// = 0

        public AnyClass()
        {
            _state = 1;
        }

        ~AnyClass()
        {
            _state = 2;
        }

        public void TestState()
        {
            if (_state != 1)
                throw new Exception("Already finalized");
        }
    }

    internal class Tester
    {
        private AnyClass _any = new AnyClass();
        private object _sync = new object();

        public void Initialize()
        {

            //lock(_sync)
                _any = new AnyClass();

            GC.Collect();
            GC.WaitForFullGCComplete();
            GC.WaitForPendingFinalizers();
        }

        public void Test()
        {
            AnyClass any;

            //lock (_sync)
                any = _any;
                //  mov         eax,dword ptr [ebp-3Ch] 
                //  mov         eax, dword ptr[eax + 4] // What if a context switch happens after this instruction?
                //  mov         dword ptr[ebp - 40h], eax

            any.TestState();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var tester = new Tester();

            Task.Run(() =>
            {
                try
                {
                    while (true)
                        tester.Initialize();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            });

            Task.Run(() =>
            {
                try
                {
                    while (true)
                        tester.Test();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            });

            Console.ReadLine();
        }
    }
}

在没有同步代码的情况下从多个线程分配和获取对象引用是否安全?

是否应该在这两种情况下都不要取消注释 lock(_sync) 语句以确保垃圾收集是安全的?

如果不是,如果在“mov eax, dword ptr[eax + 4]”之后有一个上下文切换,并且 GC 收集到 eax 中引用的对象,会发生什么。那么当“mov dword ptr[ebp - 40h], eax”最终将对象引用赋值给变量“any”时,是不是不可能引用无效了?我已经在没有锁的情况下运行了 12 个小时的代码,并且没有观察到任何不良行为。有人可以解释一下这是如何工作的吗?

我在 Windows 10 1909 上使用了 VS2017。针对 .NET 4.71 和 x86。

标签: c#.netmultithreadinggarbage-collectionsynchronization

解决方案


推荐阅读