为什么不可变对象是线程安全的?

发布于 2024-09-17 06:51:46 字数 589 浏览 17 评论 0原文

class Unit {
    private readonly string name;
    private readonly double scale;

    public Unit(string name, double scale) {
        this.name = name;
        this.scale = scale,
    }

    public string Name { get { return name; } }
    public string Scale { get { return scale; } }

    private static Unit gram = new Unit("Gram", 1.0);

    public Unit Gram { get { return gram; } }
}

多个线程可以访问Unit.Gram。为什么多个线程同时读取Unit.Gram.Title可以?

我担心的是它们指的是相同的内存位置。一个线程开始读取该内存,那么它不是“被锁定”了吗? .NET 是否处理下面这个关键部分的同步?还是我认为同时读取需要同步是错误的?

class Unit {
    private readonly string name;
    private readonly double scale;

    public Unit(string name, double scale) {
        this.name = name;
        this.scale = scale,
    }

    public string Name { get { return name; } }
    public string Scale { get { return scale; } }

    private static Unit gram = new Unit("Gram", 1.0);

    public Unit Gram { get { return gram; } }
}

Multiple threads have access to Unit.Gram. Why is it ok for multiple threads simultaneously read Unit.Gram.Title?

My concern is that they are referring to the same memory location. One thread starts reading that memory, so isn't it "locked out" then? Does the .NET handle synchronization for this critical section underneath? Or am I wrong in thinking that simultaneous reading needs synchronization?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

也只是曾经 2024-09-24 06:51:46

是什么使得对象不线程安全?如果该对象的值/状态在线程读取它时可以更改,则该对象不是线程安全的。如果在第一个线程读取该对象时第二个线程更改该对象的值,通常会发生这种情况。

根据定义,不可变对象不能更改值/状态。由于每次读取不可变对象时它都具有相同的值/状态,因此您可以让任意数量的线程毫无顾虑地读取该对象。

What makes an object not thread safe? An object is not thread safe if the value/state of that object can change while a thread is reading it. This generally happens if a second thread changes this object's value while the first thread is reading it.

An immutable object, by definition, cannot change value/state. Since every time you read an immutable object it has the same value/state, you can have any number of threads read that object with no concerns.

桃扇骨 2024-09-24 06:51:46

我认为你的问题不是关于线程安全或不变性,而是关于内存访问的(非常)低级细节。

这是一个沉重的话题,但简短的答案是:是的,两个线程(更重要的是,2 个以上的 CPU)可以同时读取(和/或写入)同一块内存。

而且只要该内存区域的内容是不可变的,所有问题都迎刃而解。当它可以改变时,就会出现一系列问题,volatile 关键字和 Interlocked 类是我们用来解决这些问题的一些工具。

I think your question turns out not to be about thread-safety or immutablity but about the (very) low level details of memory access.

And that is a hefty subject but the short answer is: Yes, two threads (and more important, 2+ CPU's) can read (and/or write) the same piece of memory simultaneously.

And as long as the content of that memory area is immutable, all problems are solved. When it can change, there is a whole range of issues, the volatile keyword and the Interlocked class are some of the tools we use to solve those.

余罪 2024-09-24 06:51:46

同时读取不需要需要同步。由于只有编写者(或读者至少一个编写者)需要同步,因此不可变对象不需要同步,因此是线程安全的。

Simultaneous reads do not need synchronization. Since synchronization is only required for writers (or readers and at least one writer), immutable objects don't require synchronization, and are therefor threadsafe.

陌路终见情 2024-09-24 06:51:46

如果对象是不可变的,那么它的状态将永远不会改变。因此,对过时数据的担忧就消失了。线程读取永远不会被锁定,因此这不是问题(死锁)

If the object is immutable its state will never change. Therefore the concerns of stale data go out the window. Thread reading is never locked in so this is a non-issue (deadlock)

街角卖回忆 2024-09-24 06:51:46

在绝大多数情况下,并发读取不需要同步(例外情况是内存映射 IO,其中从某个地址读取可能会导致副作用)。

如果并发读取确实需要同步,则几乎不可能编写有用的多线程代码。例如,要执行一段代码,处理器必须读取指令流,如果函数本身必须防止自身同时执行,您将如何编写锁定函数:)?

Concurrent reads do not require synchronization in the vast majority of cases (exceptions are things like memory mapped IO where reading from a certain address can cause side effects).

If concurrent reads did require synchronization, it would be close to impossible to write usefully multi-threaded code. To execute a piece of code for instance, the processor has to read the instruction stream, how would you write a lock function if the function itself had to protect against itself being executed concurrently :)?

情场扛把子 2024-09-24 06:51:46

读取同一内存位置只能由特定线程在一个 CPU 周期内完成。在这种情况下,读取顺序并不重要,因为基础值不会改变。因此,不存在读取不一致的可能性,因此在这种情况下不需要任何级别的同步。

Reading the same memory location can only be done in one CPU cycle by a specific thread. The order of read in this case does not matter since the underlying value does not change. Therefore there is no possibility of a read being inconsistent, so there is no need of synchronization at any level in this case.

樱花细雨 2024-09-24 06:51:46

内存管理单元是处理器中处理内存读取的部分。如果你有多个,那么千载难逢,其中两个可能会尝试在相同的十几纳秒内读取相同的内存位置,但不会出现任何问题,因为他们得到相同的答案。

Memory Management Units are the part of the processor that handles the reading of memory. If you have more than one, once in a blue moon 2 of them might try to read the same memory location in the same dozen nano-seconds, but no problems result seeing as they get the same answer.

剪不断理还乱 2024-09-24 06:51:46

除了驱动程序的映射内存等异常之外,两个线程同时读取同一内存地址没有问题。然而,当一个线程执行一些写入数据时,可能会出现问题。在这种情况下,可能会阻止其他线程读取该对象/数据。

但问题并不是由于文字的同时性(在最低的电子水平上,它们是一个接一个地出现的),问题在于对象/数据集可能会失去其一致性。通常,人们会利用节评论家来隔离一些可能无法被其他线程同时读取/写入的代码。

网上有很多例子,但请考虑以下情况,其中 price 是类的私有成员,例如 Product,它还有 2 个方法

public void setPrice(int value) {
  price = value;
  // -- point CRITIC --
  price += TAX;
}

public int getPrice() {
  return price;
}

setPrice(v) 将产品的价格设置为 v ,并用 VAT 进行调整(程序应该有 value += TAX;price = value 但这不是重点:-)

如果线程 A 写入价格 100,并且 TAX 为(固定)1 ,产品价格最终将设置为 101。但是,如果线程 B 通过 getPrice() 读取价格,而线程 A 位于 CRITIC 点,会发生什么情况?返回给B的价格将错过TAX,并且是错误的。

setPrice() 应该在关键部分(lock)内,以防止在价格设置期间对对象进行任何访问

    lock(this)
    {
      price = value;
      price += TAX;
    }

Besides exceptions like mapped memory for drivers for instance, There is no problem for two threads reading simultaneously the same memory address. A problem may arise when one thread performs some writing data though. In this case, other threads may be prevented to read that object/data.

But the problem is not due to the simultaneity of the writings (at the lowest electronic level they occur one after the other anyway), the problem is rather that the object / set of data may lose their consistency. Usually one utilize a section critic to isolate some code that may not be read/written simultaneously by other threads.

There are many examples over the Net, but consider the following, with price is a private member of a class, say Product, which has also 2 methods

public void setPrice(int value) {
  price = value;
  // -- point CRITIC --
  price += TAX;
}

public int getPrice() {
  return price;
}

setPrice(v) sets the price of a product to v, and adjust it with VAT (the program should have value += TAX; price = value but this is not the point here :-)

If thread A writes price 100, and TAX is (fixed) 1, the product price will finally be set to 101. But what happens if thread B reads the price via getPrice() while thread A is at point CRITIC? The price returned to B will miss the TAX, and be wrong.

setPrice() should within a critical section (lock), to prevent any access to the object during the setting of the price

    lock(this)
    {
      price = value;
      price += TAX;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文