Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread-safe asynchronous code in C#

I asked the question below couple of weeks ago. Now, when reviewing my question and all the answers, a very important detail jumped into my eyes: In my second code example, isn't DoTheCodeThatNeedsToRunAsynchronously() executed in the main (UI) thread? Doesn't the timer just wait a second and then post an event to the main thread? This would mean then that the code-that-needs-to-run-asynchronously isn't run asynchronously at all?!

Original question:


I have recently faced a problem multiple times and solved it in different ways, always being uncertain on whether it is thread safe or not: I need to execute a piece of C# code asynchronously. (Edit: I forgot to mention I'm using .NET 3.5!)

That piece of code works on an object that is provided by the main thread code. (Edit: Let's assume that object is thread-safe in itself.) I'll present you two ways I tried (simplified) and have these four questions:

  1. What is the best way to achieve what I want? Is it one of the two or another approach?
  2. Is one of the two ways not thread-safe (I fear both...) and why?
  3. The first approach creates a thread and passes it the object in the constructor. Is that how I'm supposed to pass the object?
  4. The second approach uses a timer which doesn't provide that possibility, so I just use the local variable in the anonymous delegate. Is that safe or is it possible in theory that the reference in the variable changes before it is evaluated by the delegate code? (This is a very generic question whenever one uses anonymous delegates). In Java you are forced to declare the local variable as final (i.e. it cannot be changed once assigned). In C# there is no such possibility, is there?

Approach 1: Thread

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);

There is one problem I had with this approach: My main thread might crash, but the process still persists in the memory due to the zombie thread.


Approach 2: Timer

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.

The local variable myObject is what I'm talking about in question 4. I've added a second assignment as an example. Imagine the timer elapses after the second assigment, will the delegate code operate on this.MyObject or that.MyObject?

like image 730
chiccodoro Avatar asked Nov 30 '22 10:11

chiccodoro


1 Answers

Whether or not either of these pieces of code is safe has to do with the structure of MyObject instances. In both cases you are sharing the myObject variable between the foreground and background threads. There is nothing stopping the foreground thread from modifying myObject while the background thread is running.

This may or may not be safe and depends on the structure of MyObject. However if you haven't specifically planned for it then it's most certainly an unsafe operation.

like image 90
JaredPar Avatar answered Dec 15 '22 00:12

JaredPar