Asynchronous code with thread support in C #

I asked a question a couple of weeks ago. Now, having examined my question and all the answers, a very important detail jumped into my eyes: in the second code example DoTheCodeThatNeedsToRunAsynchronously() is not executed in the main thread (UI)? Doesn't the timer just wait a second and then send the event to the main thread? This would mean that the asynchronous execution of the code that is necessary to run is not executed asynchronously ?!

The original question:


I recently ran into a problem several times and solved it in different ways, always being sure whether it is thread safe or not: I need to execute part of the C # code asynchronously. ( Edit: I forgot to mention that I am using .NET 3.5! )

This piece of code runs on an object that is provided by the main thread code. (Edit: Assume the object itself is thread safe.) . I will present you two ways that I tried (simplified) and ask these four questions :

  • What is the best way to achieve what I want? Is this one of two or other ways?
  • Is one of the two methods an unsafe thread (I'm afraid, like ...), and why?
  • The first approach creates a stream and passes it an object in the constructor. Is this how I should pass an object?
  • The second approach uses a timer that does not provide this feature, so I just use a local variable in anonymous deletion. Is it safe or theoretically possible that a reference in a variable changes before it is evaluated by delegate code? ( This is a very common question when you use anonymous delegates ). In Java, you are forced to declare a local variable as final (i.e., it cannot be changed after it is assigned). In C # there is no such possibility, is there?

Approach 1: Theme

 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 that I came across with this approach: my main thread may crash, but the process is still stored in 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; // ie 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 am talking about in question 4. As an example, I added a second assignment. Imagine that the timer expires after the second assignment, will the delegate code work on this.MyObject or that.MyObject ?

+4
source share
7 answers

What is the best way to achieve what I want? Is this one of two or other ways?

Both look great, but ...

Is one of the two methods an unsafe thread (I'm afraid, like ...), and why?

... they are not thread safe unless MyObject.ChangeSomeProperty() is thread safe.

The first approach creates a stream and passes it an object in the constructor. Is this how I should pass an object?

Yes. Using closure (as in your second approach) is fine too, with the added benefit you don't have to do.

The second approach uses a timer that does not provide this feature, so I just use a local variable in anonymous deletion. Is it safe or theoretically possible that a reference in a variable changes before it is evaluated by delegate code? (This is a very common question when you use anonymous delegates).

Of course, if you add myObject = null; immediately after setting timer.Elapsed , then the code in your thread will fail. But why do you have to do this? Note that changing this.MyObject will not affect the variable captured in your thread.


So how to make this thread safe? The problem is that myObject.ChangeSomeProperty(); may work in parallel with other code that changes the state of myObject . Basically there are two solutions:

Option 1 Execute MyObject.ChangeSomeProperty() in the main menu. This is the easiest solution if ChangeSomeProperty fast. You can use Dispatcher (WPF) or Control.Invoke (WinForms) to return to the user interface thread, but the easiest way is to use BackgroundWorker :

 MyObject myObject = this.MyObject; var bw = new BackgroundWorker(); bw.DoWork += (sender, args) => { // this will happen in a separate thread Thread.Sleep(1000); DoTheCodeThatNeedsToRunAsynchronously(); } bw.RunWorkerCompleted += (sender, args) => { // We are back in the UI thread here. if (args.Error != null) // if an exception occurred during DoWork, MessageBox.Show(args.Error.ToString()); // do your error handling here else myObject.ChangeSomeProperty(); } bw.RunWorkerAsync(); // start the background worker 

Option 2 Make the code in ChangeSomeProperty() thread safe with the lock keyword (inside ChangeSomeProperty , as well as inside any other method that modifies or reads the same support field).

+2
source

Regardless of whether any of these code snippets are safe with the structure of MyObject instances. In both cases, you use the MyObject variable between the front and background threads. Nothing stops the foreground thread from changing MyObject while the background thread is running.

This may or may not be safe and depends on the structure of MyObject . However, unless you specifically planned it, this is definitely an unsafe operation.

+5
source

I recommend using Task objects and restructuring the code so that the background task returns its calculated value, rather than changing some general state.

I have a blog post that discusses five different approaches to a background task ( Task , BackgroundWorker , Delegate.BeginInvoke , ThreadPool.QueueUserWorkItem and Thread ), with pros and cons for each.

To answer your questions specifically:

  • What is the best way to achieve what I want? Is this one of two or the other approach? A better solution is to use a Task object instead of a specific Thread callback or timer. See my blog post for all reasons, but in the end: Task supports returning results , callbacks upon completion , proper error handling, and integration with the universal undo system in .NET.
  • Is one of the two methods an unsafe thread (I'm afraid, like ...), and why? As others have claimed, it totally depends on whether MyObject.ChangeSomeProperty thread safe. When working with asynchronous systems, it is easier to talk about thread safety when each asynchronous operation does not change the general state and rather returns the result.
  • The first approach creates a stream and passes it an object in the constructor. Is this how I should pass an object? Personally, I prefer to use a lambda binding, which is safer in type (does not require casting).
  • The second approach uses a timer that does not provide this feature, so I just use a local variable in anonymous deletion. Is it safe or theoretically possible that a reference in a variable changes before it is evaluated by delegate code? Lambdas (and delegate expressions) are bound to variables, not values, so the answer is yes: the link may change before it is used by the delegate. If the link can change, then the usual solution is to create a separate local variable that is used only by the lambda expression,

as such:

 MyObject myObject = this.MyObject; ... timer.AutoReset = false; // ie only run the timer once. var localMyObject = myObject; // copy for lambda timer.Elapsed += new System.Timers.ElapsedEventHandler( delegate(object sender, System.Timers.ElapsedEventArgs e) { DoTheCodeThatNeedsToRunAsynchronously(); localMyObject.ChangeSomeProperty(); }); // Now myObject can change without affecting timer.Elapsed 

Tools like ReSharper will try to determine if the local variables associated with lambdas can change, and will warn you if it detects this situation.

My recommended solution (using Task ) would look something like this:

 var ui = TaskScheduler.FromCurrentSynchronizationContext(); var localMyObject = this.myObject; Task.Factory.StartNew(() => { // Run asynchronously on a ThreadPool thread. Thread.Sleep(1000); // TODO: review if you *really* need this return DoTheCodeThatNeedsToRunAsynchronously(); }).ContinueWith(task => { // Run on the UI thread when the ThreadPool thread returns a result. if (task.IsFaulted) { // Do some error handling with task.Exception } else { localMyObject.ChangeSomeProperty(task.Result); } }, ui); 

Note that since the UI thread is the one that calls MyObject.ChangeSomeProperty , this method should not be thread safe. Of course, DoTheCodeThatNeedsToRunAsynchronously still needs to be thread safe.

+4
source

Your first attempt is pretty good, but the stream continued to exist even after the application IsBackground , because you did not set the IsBackground property to true ... here is a simplified (and improved) version of your code:

 MyObject myObject = this.MyObject; Thread t = new Thread(()=> { Thread.Sleep(1000); // wait a second (for a specific reason) DoTheCodeThatNeedsToRunAsynchronously(); myObject.ChangeSomeProperty(); }); t.IsBackground = true; t.Start(); 

As for thread safety: it's hard to say if your program is working properly when multiple threads are running at the same time because you are not showing us any match points in your example. It is very likely that you will encounter concurrency problems if your program has competition on MyObject .

Java has the final keyword, and C # has the corresponding keyword named readonly , but neither final nor readonly guarantees that the state of the mutable object will be consistent between threads. The only thing these keywords do is ensure that you do not change the link that the object points to. If two threads have read / write conflicts on the same object, then to ensure thread safety, you need to perform some synchronization or atom operations.

Update

OK, if you change the link that MyObject points to, then your dispute is now included in MyObject . I am sure that my answer will not be 100% in your real situation, but given the example code given, I can tell you what will happen:

You are not guaranteed which object will be modified: it can be that.MyObject or this.MyObject . This is true if you are working with Java or C #. A scheduler can schedule your thread / timer to run before, after, or during a second assignment. If you are counting on a specific execution order, then you need to do something to ensure that the execution order is executed. Usually something is the connection between the flows in the form of a signal: a ManualResetEvent , Join or something else.

Here is an example connection:

 MyObject myObject = this.MyObject; Thread task = new Thread(()=> { Thread.Sleep(1000); // wait a second (for a specific reason) DoTheCodeThatNeedsToRunAsynchronously(); myObject.ChangeSomeProperty(); }); task.IsBackground = true; task.Start(); task.Join(); // blocks the main thread until the task thread is finished myObject = that.MyObject; // the assignment will happen after the task is complete 

Here is an example of ManualResetEvent :

 ManualResetEvent done = new ManualResetEvent(false); MyObject myObject = this.MyObject; Thread task = new Thread(()=> { Thread.Sleep(1000); // wait a second (for a specific reason) DoTheCodeThatNeedsToRunAsynchronously(); myObject.ChangeSomeProperty(); done.Set(); }); task.IsBackground = true; task.Start(); done.WaitOne(); // blocks the main thread until the task thread signals it done myObject = that.MyObject; // the assignment will happen after the task is done 

Of course, in this case it’s pointless even to create several threads, since you do not allow them to start at the same time. One way to avoid this is to not change the link to MyObject after you start the stream, then you do not need Join or WaitOne on ManualResetEvent .

So this leads me to the question: why are you assigning a new MyObject ? Is this part of a for loop that runs multiple threads to perform multiple asynchronous tasks?

+3
source

"Thread-safe" is a cunning beast. With both of your statements, the problem is that the MyObject stream you are using can be modified / read by multiple threads so that the state looks inconsistent or causes your stream to be incompatible with the actual state.

For example, say that your MyObject.ChangeSomeproperty() MUST be called before MyObject.DoSomethingElse() , or it throws. With any of your approaches, there is nothing to stop any other thread from calling DoSomethingElse() before the thread that calls ChangeSomeProperty() finishes.

Or, if ChangeSomeProperty() called by two threads, and it (internally) changes state, the context switch of the thread can happen when the first thread is in the middle of its operation, and the end result is that the actual new state after both threads are "wrong."

However, by itself, none of your approaches is essentially threadlike; it just needs to make sure that the state change is serialized and that access to the state always gives a consistent result.

Personally, I would not use the second approach. If you are having problems with zombie streams, set the IsBackground parameter to true in the stream.

+3
source

A more serious security issue here, in my opinion, could be 1 second of sleep. If it is necessary to synchronize with any other operation (giving it time to complete), I highly recommend using the correct synchronization pattern, rather than relying on Sleep. Monitor.Pulse or AutoResetEvent are two common ways to achieve synchronization. Both should be used carefully, as it is easy to enter subtle race conditions. However, using Sleep for synchronization is a race condition awaiting its appearance.

In addition, if you want to use a thread (and do not have access to a parallel task library in .NET 4.0), then ThreadPool.QueueUserWorkItem is preferred for short-term tasks. Thread pool threads will also not hang the application if it dies, if there is no deadlock that prevents the death of the non-phonic thread.

+2
source

One thing not mentioned so far: The choice of streaming methods depends heavily on what DoTheCodeThatNeedsToRunAsynchronously() does.

Different .NET flow approaches are suitable for different requirements. One very big problem is whether this method will finish quickly or will take some time (does it last for long or for a long time?).

Some .NET streaming mechanisms, such as ThreadPool.QueueUserWorkItem() , are used for short-lived threads. They avoid the cost of creating a thread using "recycled" threads, but the number of threads that it will process is limited, so a long-term task should not process ThreadPool threads.

Other possible use cases:

  • ThreadPool.QueueUserWorkItem() is a convenient tool for starting and restarting small tasks in the ThreadPool thread.

  • System.Threading.Tasks.Task is a new .NET 4 feature that simplifies small tasks in asynchronous / parallel mode.

  • Delegate.BeginInvoke() and Delegate.EndInvoke() ( BeginInvoke() will run the code asynchronously, but it is important that you guarantee EndInvoke() to avoid potential resource leaks, as well as ThreadPool based topics that I consider.

  • System.Threading.Thread , as shown in your example. Threads provide the most control, but are also more expensive than other methods, so they are ideal for long-term tasks or multi-threading focused on parts.

In general, my personal preferences were to use Delegate.BeginInvoke()/EndInvoke() - it seems to provide a good balance between control and ease of use.

+1
source

All Articles