Требуется ли для присвоения и получения ссылки на объект из нескольких потоков код синхронизации? - PullRequest
1 голос
/ 27 февраля 2020

Отказ от ответственности: этот код работает два потока непрерывно навсегда. Запускайте на свой страх и риск.

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();
        }
    }
}

Безопасно ли назначать и получать ссылку на объект из нескольких потоков без кода синхронизации?

Если в обоих случаях оператор блокировки (_syn c) не должен быть прокомментирован для обеспечения безопасности сборки мусора?

Если нет, что произойдет, если после переключения контекста «mov eax, dword ptr [eax + 4]» и G C собирает объект, на который ссылается eax. Тогда, когда "mov dword ptr [ebp - 40h], eax", наконец, присваивает ссылку на объект переменной "any", не может ли ссылка быть недействительной? Я запустил код в течение 12 часов без блокировки и не заметил плохого поведения. Может кто-нибудь объяснить, как это работает?

Я использовал VS2017 на Windows 10 1909. Targeted. NET 4.71 и x86.

...