gpt4 book ai didi

c# - 为什么可以在同一个类中创建的另一个线程中访问局部变量?

转载 作者:可可西里 更新时间:2023-11-01 07:48:46 24 4
gpt4 key购买 nike

我真的找不到关于这个确切主题的任何内容,所以如果问题已经存在,请引导我走向正确的方向。

根据我对 .NET 的了解,不可能跨不同线程访问变量(如果该语句有误,请纠正我,这正是我在某处读到的)。

然而,现在在这个代码示例中,它似乎不应该工作:

class MyClass
{
public int variable;

internal MyClass()
{
Thread thread = new Thread(new ThreadStart(DoSomething));
thread.IsBackground = true;
thread.Start();
}

public void DoSomething()
{
variable = 0;
for (int i = 0; i < 10; i++)
variable++;

MessageBox.Show(variable.ToString());
}
}

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private void SomeMethod();
{
MyClass mc = new MyClass();
}
}

当我跑 SomeMethod() .NET 不应该抛出异常,因为创建的对象 mc在与 mc 中创建的线程不同的线程中运行-initializer 并且这个新线程试图访问 mc 的局部变量?
MessageBox显示 10正如(不是)预期的那样,但我不确定为什么这会起作用。

也许我不知道要搜索什么,但是我找不到可以解决这个问题的线程主题,但也许我对变量和线程的想法是错误的。

最佳答案

From what I have learned about .NET, it is not possible to access variables across different threads. Please correct me if that statement is wrong, it's just what I have read somewhere.



该陈述是完全错误的,因此请将此视为您的更正。

您可能在某处读到 局部变量 不能跨线程访问。该陈述也是错误的,但通常被陈述。正确的说法是局部变量不是
  • 在异步方法中
  • 在迭代器块中(即具有 yield returnyield break 的方法)
  • 匿名函数的封闭外部变量

  • 不能被多个线程访问。甚至这种说法也有点狡猾。有一些方法可以使用指针和 unsafe 来做到这一点。代码块,但尝试这样做是一个非常糟糕的主意。

    我还注意到您的问题询问了局部变量,但随后给出了一个字段的示例。字段的定义是 不是 一个局部变量。根据定义,局部变量是方法体的局部变量。 (或构造函数体、索引器体等)确保您清楚这一点。本地的定义特征不是“在堆栈上”或类似的东西;本地的“本地”部分是它的名称在方法主体之外没有意义。

    在一般情况下:变量是指内存的存储位置。一个线程是一个进程中的一个控制点,一个进程中的所有线程共享同一个内存;这就是使它们成为线程而不是进程的原因。所以一般来说,所有变量都可以在任何时候以任何顺序被多个线程访问,除非有某种机制来防止这种情况发生。

    让我再说一遍,只是为了确保您在头脑中绝对清楚:考虑单线程程序的正确方法是所有变量都是稳定的,除非某些事情使它们发生变化。考虑多线程程序的正确方法是,所有变量都在没有特定顺序的情况下不断变化,除非某些东西使它们保持静止或有序。 这就是为什么多线程的共享内存模型如此困难的根本原因 ,因此为什么你应该避免它。

    在您的特定示例中,两个线程都可以访问 this ,因此两个线程都可以看到变量 this.variable .您没有实现任何机制来防止这种情况发生,因此两个线程都可以以任何顺序写入和读取该变量,确实受到很少的约束。您可以实现一些机制来驯服这种行为:
  • 将变量标记为 ThreadStatic .这样做会导致在每个线程上创建一个新变量。
  • 将变量标记为 volatile .这样做对如何观察读取和写入的顺序施加了某些限制,并且还对编译器或 CPU 进行的可能导致意外结果的优化施加了某些限制。
  • 放一个 lock围绕变量的每次使用进行声明。
  • 首先不要共享变量。

  • 除非您对多线程和处理器优化有深入的了解,否则我建议您不要选择除后者之外的任何选项。

    现在,假设您确实希望确保在另一个线程上访问该变量失败。您可以让构造函数捕获创建线程的线程 ID 并将其隐藏起来。然后您可以通过属性 getter/setter 访问该变量,其中 getter 和 setter 检查当前线程 ID,如果它与原始线程 ID 不同,则抛出异常。

    本质上,它的作用是推出您自己的单线程单元线程模型。 “单线程单元”对象是一个只能在创建它的线程上合法访问的对象。 (你买了一台电视,你把它放在你的公寓里,只有你公寓里的人才能看你的电视。)单线程公寓vs多线程公寓vs免费线程的细节变得相当复杂;有关更多背景,请参阅此问题。

    Could you explain STA and MTA?

    这就是为什么,例如,您绝不能从工作线程访问在 UI 线程上创建的 UI 元素; UI 元素是 STA 对象。

    关于c# - 为什么可以在同一个类中创建的另一个线程中访问局部变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18770414/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com