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

2024-01-31

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

根据我对 .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-初始化程序和这个新线程正在尝试访问局部变量mc?

The MessageBox shows 10正如(不)预期的那样,但我不确定为什么这应该起作用。

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


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

该声明完全错误,因此请将此视为您的更正。

你可能在某处读到过局部变量不能跨不同线程访问。该声明是also错误的,但通常是这样说的。正确的说法是局部变量不是

  • 在异步方法中
  • 在迭代器块中(即带有yield return or yield break)
  • 匿名函数的封闭外部变量

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

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

一般情况下:变量是存储位置指的是memory。一个线程是一个过程中的控制点,并且进程中的所有线程共享相同的内存;这就是让他们threads并不是流程。所以一般来说,所有变量都可以被多个线程在任何时间、以任何顺序访问,除非建立某种机制来防止这种情况发生.

让我再说一遍,只是为了确保您头脑中绝对清楚:考虑单线程程序的正确方法是所有变量都是stable除非有什么事情让他们改变。考虑多线程程序的正确方法是所有变量都是不断变异 in 没有特别的顺序除非有什么东西让他们保持静止或秩序井然。这就是多线程的共享内存模型如此困难的根本原因,以及为什么你应该避免它。

在您的特定示例中,两个线程都可以访问this,因此两个线程都可以看到变量this.variable。您没有实现任何机制来防止这种情况,因此两个线程都可以按任何顺序写入和读取该变量,实际上受到的约束很少。您可以实施一些机制来抑制这种行为:

  • 将变量标记为ThreadStatic。这样做会导致在每个线程上创建一个新变量。
  • 将变量标记为volatile。这样做会对如何观察读取和写入的顺序施加某些限制,并且还会对编译器或 CPU 进行的优化施加某些限制,从而可能导致意外结果。
  • Put a lock围绕变量的每个用法的声明。
  • 首先不要共享变量。

除非你有一个deep由于了解多线程和处理器优化,我建议不要选择除后者之外的任何选项。

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

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

您能解释一下 STA 和 MTA 吗? https://stackoverflow.com/questions/127188/could-you-explain-sta-and-mta

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么可以在同一个类中创建的另一个线程中访问局部变量? 的相关文章

  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • 是否可以强制 XMLWriter 将元素写入单引号中?

    这是我的代码 var ptFirstName tboxFirstName Text writer WriteAttributeString first ptFirstName 请注意 即使我使用 ptFirstName 也会以双引号结束 p
  • 未解决的包含:“cocos2d.h” - Cocos2dx

    当我在 Eclipse 中导入 cocos2dx android 项目时 我的头文件上收到此警告 Unresolved inclusion cocos2d h 为什么是这样 它实际上困扰着我 该项目可以正确编译并运行 但我希望这种情况消失
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • C - 找到极限之间的所有友好数字

    首先是定义 一对友好的数字由两个不同的整数组成 其中 第一个整数的除数之和等于第二个整数 并且 第二个整数的除数之和等于第一个整数 完美数是等于其自身约数之和的数 我想做的是制作一个程序 询问用户一个下限和一个上限 然后向他 她提供这两个限
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • 如何将图像和 POST 数据上传到 Azure 移动服务 ApiController 终结点?

    我正在尝试上传图片and POST表单数据 尽管理想情况下我希望它是json 到我的端点Azure 移动服务应用 我有ApiController method HttpPost Route api upload databaseId sea
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • Qt moc 在头文件中实现?

    是否可以告诉 Qt MOC 我想声明该类并在单个文件中实现它 而不是将它们拆分为 h 和 cpp 文件 如果要在 cpp 文件中声明并实现 QObject 子类 则必须手动包含 moc 文件 例如 文件main cpp struct Sub
  • 如何将单个 char 转换为 int [重复]

    这个问题在这里已经有答案了 我有一串数字 例如 123456789 我需要提取它们中的每一个以在计算中使用它们 我当然可以通过索引访问每个字符 但是如何将其转换为 int 我研究过 atoi 但它需要一个字符串作为参数 因此 我必须将每个字
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • 将 unsigned char * (uint8_t *) 转换为 const char *

    我有一个带有 uint8 t 参数的函数 uint8 t ihex decode uint8 t in size t len uint8 t out uint8 t i hn ln for i 0 i lt len i 2 hn in i
  • 如何使我的表单标题栏遵循 Windows 深色主题?

    我已经下载了Windows 10更新包括黑暗主题 文件资源管理器等都是深色主题 但是当我创建自己的 C 表单应用程序时 标题栏是亮白色的 如何使我自己的桌面应用程序遵循我在 Windows 中设置的深色主题 你需要调用DwmSetWindo
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 如何让Gtk+窗口背景透明?

    我想让 Gtk 窗口的背景透明 以便只有窗口中的小部件可见 我找到了一些教程 http mikehearn wordpress com 2006 03 26 gtk windows with alpha channels https web
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount
  • 为什么我收到“找不到编译动态表达式所需的一种或多种类型。”?

    我有一个已更新的项目 NET 3 5 MVC v2 到 NET 4 0 MVC v3 当我尝试使用或设置时编译出现错误 ViewBag Title财产 找不到编译动态表达式所需的一种或多种类型 您是否缺少对 Microsoft CSharp
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce

随机推荐