代码之家  ›  专栏  ›  技术社区  ›  Enrico Massone

C:如果两个线程试图同时读写同一个字段(假设该字段小于或等于32位),会发生什么情况?

  •  0
  • Enrico Massone  · 技术社区  · 6 年前

    根据 Joe Albahari's book Threading in C# 读写大小小于或等于32位的字段是一种原子操作:这意味着在这种情况下,不可能以 撕破的阅读 ( here 您可以找到一种简单的方法,通过使用十进制字段来重现一个被撕破的读数)。

    鉴于此,请考虑以下C控制台应用程序:

    using System;
    using System.Threading;
    
    namespace ConsoleApp2
    {
      class Program
      {
        static void Main(string[] args)
        {
          var obj = new Test();
          var random = new Random();
    
          var thread1 = new Thread(() =>
          {
            while (true)
            {
              Console.WriteLine($"The boolean value is {obj.field}");
            }
          });
    
          var thread2 = new Thread(() =>
          {
            while (true)
            {
              obj.field = (random.Next() % 2) == 0;
            }
          });
    
          thread1.Start();
          thread2.Start();
        }
      }
    
      class Test
      {
        public bool field;
      }
    }
    

    我的问题是:当我运行这样一个程序时,包含两个线程同时写入和读取字段值的内存地址中到底发生了什么?这样做是否可能破坏其价值?

    根据我的理解,在同一时间有对同一内存地址的并发访问:

    1. 我可以得到任何类型的运行时异常吗?
    2. 底层处理器是否能够在不出错的情况下处理这样的场景?

    以更一般的方式提出问题:当两个线程同时读写32位值时 唯一可能的问题 有吗? 保证正在读取的值(我的意思是,由于并发写入操作,读取的值是完全不确定的)?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Steve    6 年前

    1.我可以得到任何类型的运行时异常吗?

    不。现代处理器有一种阻止其他内核对同一地址进行独占(写入)访问的方法,类似于旋转锁。(实际实现因处理器而异)

    2.底层处理器是否能够在不出错的情况下处理这种情况?

    是的,所有对齐的4字节写入(或64位操作系统的8字节)都保证是原子的,从某种意义上说,您不能得到损坏的数据(core1的2字节和core2的2字节)。但是,如果写入为>8字节或超出对齐边界(例如大整数),那么如果在没有锁定的情况下完成写入,则可能会进入损坏的内存情况。

    OFC总是有可能导致处理器实现出错,在这种情况下,您就是SOL