C#:假设字段小于或等于32位,当两个线程试图同时读取和写入同一字段时会发生什么情况

C#:假设字段小于或等于32位,当两个线程试图同时读取和写入同一字段时会发生什么情况,c#,multithreading,concurrency,C#,Multithreading,Concurrency,根据该理论,读取和写入大小小于或等于32位的字段是一种原子操作:这意味着在这种情况下,不可能以撕裂读取结束(您可以找到一种使用十进制字段复制撕裂读取的简单方法) 考虑到以下C控制台应用程序: using System; using System.Threading; namespace ConsoleApp2 { class Program { static void Main(string[] args) { var obj = new Test();

根据该理论,读取和写入大小小于或等于32位的字段是一种原子操作:这意味着在这种情况下,不可能以撕裂读取结束(您可以找到一种使用十进制字段复制撕裂读取的简单方法)

考虑到以下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;
  }
}
我的问题是:当我运行这样一个程序时,包含两个线程同时写入和读取的字段值的内存地址中到底发生了什么?这样做是否可能破坏其价值

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

  • 这样做可以得到任何类型的运行时异常吗
  • 底层处理器是否能够无错误地处理此类场景
  • 以更一般的方式提出这个问题:当两个线程同时读写一个32位的值时,唯一可能的问题是,没有保证读取的值(我的意思是,由于并发写入操作,读取的值是完全不确定的)

    1.这样做是否可以获得任何类型的运行时异常

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

    2.底层处理器是否能够无错误地处理此类场景

    是的,所有对齐的4字节写入(或64位操作系统的8字节写入)都保证是原子的,从某种意义上说,您无法获取损坏的数据(2字节来自core1,2字节来自core2)。但是,如果写入大于8字节或超出对齐边界(例如,大整数),则如果在没有锁定的情况下写入,则可能会导致内存损坏

    Ofc总是有处理器实现出错的机会,在这种情况下,您就是SOL

    1.这样做是否可以获得任何类型的运行时异常

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

    2.底层处理器是否能够无错误地处理此类场景

    是的,所有对齐的4字节写入(或64位操作系统的8字节写入)都保证是原子的,从某种意义上说,您无法获取损坏的数据(2字节来自core1,2字节来自core2)。但是,如果写入大于8字节或超出对齐边界(例如,大整数),则如果在没有锁定的情况下写入,则可能会导致内存损坏


    Ofc总是有处理器实现出错的可能,在这种情况下,即使您具有真正的并发性(多个内核),也会有“缓存一致性”的整个主题,以确保内核不会看到损坏的写入。但是,尝试用Q+a格式进行覆盖是相当复杂的。即使您具有真正的并发性(多个核心),也有一个完整的主题“缓存一致性”,以确保核心不会看到损坏的写入。但尝试用Q+a格式进行覆盖是相当复杂的。@dymanoid我认为你不能在c#中进行未对齐的访问,所以这是不可能的,而且访问也不能保证是原子的。@EnricoMassone,这个答案不正确,因为它没有覆盖未对齐的访问。请参阅并阅读(尽管它被标记为C++,提供的信息非常有用)。永远不知道你能那样射中自己的脚lol@dymanoid我认为你不能在c#中进行未对齐的访问,所以这是不可能的,而且访问不能保证是原子的。@EnricoMassone,这个答案是不正确的,因为它不包括未对齐的访问。请参阅并阅读(尽管它被标记为C++,提供的信息非常有用)。永远不知道你能像那样射中自己的脚,哈哈