C#中的线程安全异步代码

chi*_*oro 4 c# multithreading timer thread-safety .net-3.5

几个星期前我问了下面的问题.现在,在回顾我的问题和所有答案时,一个非常重要的细节跳进了我的眼睛:在我的第二个代码示例中,是不是DoTheCodeThatNeedsToRunAsynchronously()在主(UI)线程中执行?计时器只是等待一秒钟,然后将事件发布到主线程?这意味着那些需要异步运行的代码根本不是异步运行的?!

原始问题:


我最近遇到过多次问题并以不同的方式解决它,总是不确定它是否是线程安全的:我需要异步执行一段C#代码.(编辑:我忘了提到我使用的是.NET 3.5!)

这段代码适用于主线程代码提供的对象.(编辑:我们假设该对象本身就是线程安全的.)我将向您介绍我尝试过的两种方法(简化)并提出以下四个问题:

  1. 实现我想要的最好方法是什么?它是两种或另一种方法之一吗?
  2. 两种方式中的一种不是线程安全的(我担心两者......)以及为什么?
  3. 第一种方法创建一个线程并将其传递给构造函数中的对象.这是我应该如何传递对象?
  4. 第二种方法使用一个不提供这种可能性的计时器,所以我只使用匿名委托中的局部变量.这是安全还是理论上可以在变量中的引用在委托代码评估之前发生变化?(每当使用匿名代表时,这是一个非常通用的问题).在Java中,您必须将局部变量声明为final(即一旦分配就不能更改).在C#中没有这种可能性,有吗?

方法1:线程

new Thread(new ParameterizedThreadStart(
    delegate(object parameter)
    {
        Thread.Sleep(1000); // wait a second (for a specific reason)

        MyObject myObject = (MyObject)parameter;

        DoTheCodeThatNeedsToRunAsynchronously();
        myObject.ChangeSomeProperty();

    })).Start(this.MyObject);
Run Code Online (Sandbox Code Playgroud)

这种方法有一个问题:我的主线程可能崩溃,但由于僵尸线程,进程仍然存在于内存中.


方法2:定时器

MyObject myObject = this.MyObject;

System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.AutoReset = false; // i.e. only run the timer once.
timer.Elapsed += new System.Timers.ElapsedEventHandler(
    delegate(object sender, System.Timers.ElapsedEventArgs e)
    {
        DoTheCodeThatNeedsToRunAsynchronously();
        myObject.ChangeSomeProperty();
    });

DoSomeStuff();
myObject = that.MyObject; // hypothetical second assignment.
Run Code Online (Sandbox Code Playgroud)

myObject我正在讨论局部变量问题4.我添加了第二个赋值作为示例.想象一下,在第二个分配之后计时器过去了,代表代码是否会运行this.MyObject或that.MyObject?

Jar*_*Par 5

这些代码中的任何一个是否安全都与MyObject实例的结构有关.在这两种情况下,您都myObject在前台和后台线程之间共享变量.myObject在后台线程运行时,没有什么能阻止前台线程修改.

这可能是也可能不安全,取决于结构MyObject.但是,如果您没有专门为此计划,那么它肯定是一种不安全的操作.