Resource locking between iterations of the main thread (Async/Await) - c#

Let's say I have a form with two buttons (button1 and button2) and a resource object (r). The resource has its own locking and unlocking code to handle concurrency. The resource could be modified by any thread.
When button1 is clicked, its handler does some modifying of r itself and then calls _IndependentResourceModifierAsync() asynchronously which does some modifying of r in a spawned task. _IndependentResourceModifierAsync() acquires r's lock before doing this. Also because the handler is messing with r itself, it acquires r's lock too.
When button2 is clicked, it just calls _IndependentResourceModifierAsync() directly. It does no locking itself.
As you know, the handlers for the buttons will always execute on the main thread (except for the spawned Task).
There's two things that I want to guarantee:
If either button1 or button2 is clicked while the resource is locked by the main thread, an exception will be thrown. (Can't use a Monitor or Mutex because they are thread driven)
The nesting of locks from button1_Click() through _IndependentResourceModiferAsync() should not cause a deadlock. (Can't use a Semaphore).
Basically, I think what I'm looking for is a "stack-based lock" if such a thing exists or is even possible. Because when an async method continues after an await, it restores stack state. I did a lot of searching for anyone else who has had this problem but came up dry. That likely means I'm over-complicating things, but I am curious what people have to say about it. There might be something really obvious I'm missing. Many thanks.
public class Resource
{
public bool TryLock();
public void Lock();
public void Unlock();
...
}
public class MainForm : Form
{
private Resource r;
private async void button1_Click(object sender, EventArgs e)
{
if (!r.TryLock())
throw InvalidOperationException("Resource already acquired");
try
{
//Mess with r here... then call another procedure that messes with r independently.
await _IndependentResourceModiferAsync();
}
finally
{
r.Unlock();
}
}
private async void button2_Click(object sender, EventArgs e)
{
await _IndependentResourceModifierAsync();
}
private async void _IndependentResourceModiferAsync()
{
//This procedure needs to check the lock too because he can be called independently
if (!r.TryLock())
throw InvalidOperationException("Resource already acquired");
try
{
await Task.Factory.StartNew(new Action(() => {
// Mess around with R for a long time.
}));
}
finally
{
r.Unlock();
}
}
}

The resource has its own locking and unlocking code to handle concurrency. The resource could be modified by any thread.
There's a yellow flag. I find that a design where you protect resources (rather than have them protect themselves) is usually better in the long run.
When button1 is clicked, its handler does some modifying of r itself and then calls _IndependentResourceModifierAsync() asynchronously which does some modifying of r in a spawned task. _IndependentResourceModifierAsync() acquires r's lock before doing this. Also because the handler is messing with r itself, it acquires r's lock too.
And there's a red flag. Recursive locks are almost always a bad idea. I explain my reasoning on my blog.
There's also another warning I picked up regarding the design:
If either button1 or button2 is clicked while the resource is locked by the main thread, an exception will be thrown. (Can't use a Monitor or Mutex because they are thread driven)
That doesn't sound right to me. Is there any other way to do this? Disabling buttons as the state changes seems like a much nicer approach.
I strongly recommend refactoring to remove the requirement for lock recursion. Then you can use SemaphoreSlim with WaitAsync to asynchronously acquire the lock and Wait(0) for the "try-lock".
So your code would end up looking something like this:
class Resource
{
private readonly SemaphoreSlim mutex = new SemaphoreSlim(1);
// Take the lock immediately, throwing an exception if it isn't available.
public IDisposable ImmediateLock()
{
if (!mutex.Wait(0))
throw new InvalidOperationException("Cannot acquire resource");
return new AnonymousDisposable(() => mutex.Release());
}
// Take the lock asynchronously.
public async Task<IDisposable> LockAsync()
{
await mutex.WaitAsync();
return new AnonymousDisposable(() => mutex.Release());
}
}
async void button1Click(..)
{
using (r.ImmediateLock())
{
... // mess with r
await _IndependentResourceModiferUnsafeAsync();
}
}
async void button2Click(..)
{
using (r.ImmediateLock())
{
await _IndependentResourceModiferUnsafeAsync();
}
}
async Task _IndependentResourceModiferAsync()
{
using (await r.LockAsync())
{
await _IndependentResourceModiferUnsafeAsync();
}
}
async Task _IndependentResourceModiferUnsafeAsync()
{
... // code here assumes it owns the resource lock
}
I did a lot of searching for anyone else who has had this problem but came up dry. That likely means I'm over-complicating things, but I am curious what people have to say about it.
For a long time, it wasn't possible (at all, period, full-stop). With .NET 4.5, it is possible, but it's not pretty. It's very complicated. I'm not aware of anyone actually doing this in production, and I certainly don't recommend it.
That said, I have been playing around with asynchronous recursive locks as an example in my AsyncEx library (it will never be part of the public API). You can use it like this (following the AsyncEx convention of already-cancelled tokens acting synchronously):
class Resource
{
private readonly RecursiveAsyncLock mutex = new RecursiveAsyncLock();
public RecursiveLockAsync.RecursiveLockAwaitable LockAsync(bool immediate = false)
{
if (immediate)
return mutex.LockAsync(new CancellationToken(true));
return mutex.LockAsync();
}
}
async void button1Click(..)
{
using (r.LockAsync(true))
{
... // mess with r
await _IndependentResourceModiferAsync();
}
}
async void button2Click(..)
{
using (r.LockAsync(true))
{
await _IndependentResourceModiferAsync();
}
}
async Task _IndependentResourceModiferAsync()
{
using (await r.LockAsync())
{
...
}
}
The code for RecursiveAsyncLock is not very long but it is terribly mind-bending to think about. It starts with the implicit async context that I describe in detail on my blog (which is hard to understand just by itself) and then uses custom awaitables to "inject" code at just the right time in the end-user async methods.
You're right at the edge of what anyone has experimented with. RecursiveAsyncLock is not thoroughly tested at all, and likely never will be.
Tread carefully, explorer. Here be dragons.

I believe asynchronous re-entrant locking that behaves reasonably well is impossible. This is because when you start an asynchronous operation, you're not required to immediately await it.
For example, imagine you changed your event handler to something like this:
private async void button1_Click(object sender, EventArgs e)
{
if (!r.TryLock())
throw InvalidOperationException("Resource already acquired");
try
{
var task = _IndependentResourceModiferAsync();
// Mess with r here
await task;
}
finally
{
r.Unlock();
}
}
If the lock was asynchronously re-entrant, the code that works with r in the event handler and the code in the invoked asynchronous method could work at the same time (because they can run on different threads). This means such lock wouldn't be safe.

I think you should look at SemaphoreSlim (with a count of 1):
It isn't re-entrant (it's not owned by a thread)
It supports asynchronous waiting (WaitAsync)
I don't have time to check through your scenario right now, but I think it would fit.
EDIT: I've just noticed this bit of the question:
Because when an async method continues after an await, it restores stack state.
No, it absolutely doesn't. That's easily to show - add an async method which responds to a button click like this:
public void HandleClick(object sender, EventArgs e)
{
Console.WriteLine("Before");
await Task.Delay(1000);
Console.WriteLine("After");
}
Set a break point on both of your Console.WriteLine calls - you'll notice that before the await, you've got a stack trace including the "button handling" code in WinForms; afterwards the stack will look very different.

Related

Invoke inside Task.Run, how to solve deadlock?

I have a static method, which can be called from anywhere. During execution it will encounter Invoke. Obviously when this method is called from UI thread it will deadlock.
Here is a repro:
public static string Test(string text)
{
return Task.Run(() =>
{
App.Current.Dispatcher.Invoke(() => { } );
return text + text;
}).Result;
}
void Button_Click(object sender, RoutedEventArgs e) => Test();
I've read multiple questions and like 10 answers of #StephenCleary (even some blogs linked from those), yet I fail to understand how to achieve following:
have a static method, which is easy to call and obtain result from anywhere (e.g. UI event handlers, tasks);
this method should block the caller and after it the caller code should continue run in the same context;
this method shouldn't freeze UI.
The closest analogy to what Test() should behave like is MessageBox.Show().
Is it achieve-able?
P.S.: to keep question short I am not attaching my various async/await attempts as well as one working for UI calls, but terrible looking using DoEvents one.
You can not.
Even just 2 of those 3 requirements can't be achieved together - "this method should block the caller" is in conflict with "this method shouldn't freeze UI".
You have to make this method either asynchronous in some way (await, callback) or make it executable in small chunks to block UI only for short periods of time using for example timer to schedule each step.
Just to reiterate what you already know - you can't block thread and call it back at the same time as discusses in many questions like - await works but calling task.Result hangs/deadlocks.
To achieve something what MessageBox does (but without creating window) one can do something like this:
public class Data
{
public object Lock { get; } = new object();
public bool IsFinished { get; set; }
}
public static bool Test(string text)
{
var data = new Data();
Task.Run(() =>
{
Thread.Sleep(1000); // simulate work
App.Current.Dispatcher.Invoke(() => { });
lock (data.Lock)
{
data.IsFinished = true;
Monitor.Pulse(data.Lock); // wake up
}
});
if (App.Current.Dispatcher.CheckAccess())
while (!data.IsFinished)
DoEvents();
else
lock (data.Lock)
Monitor.Wait(data.Lock);
return false;
}
static void DoEvents() // for wpf
{
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Func<object, object>(o =>
{
((DispatcherFrame)o).Continue = false;
return null;
}), frame);
Dispatcher.PushFrame(frame);
}
The idea is simple: check if current thread need invoke (UI thread) and then either run DoEvents loop or block thread.
Test() can be called from UI thread or from another task.
It works (not fully tested though), but it's crappy. I hope this will make my requirements clear and I still need the answer to my question if there is any better "no, you can't do this" ;)

Asynchronous Thread Lifetime & WPF UI Update

On button click I have fired call to StartContinuousThread which keeps polling the server every one second.
public class ThreadsWindow
{
CancellationTokenSource wtoken = new CancellationTokenSource();
private void btnStartTest_Click(object sender, RoutedEventArgs e)
{
StartContinuousThread();
}
void StartContinuousThread()
{
while(true)
{
var fact = Task.Factory.StartNew(() =>
{
CallServer();
Task.Delay(1000, wtoken.Token);
},
wtoken.Token);
}
}
}
StartContinuousThread starts executing, but btnStartTest_Click event handler finishes its execution.
How StartContinuousThread method would be able to update UI in this
case?
I wonder whether StartContinuousThread is also terminated with event handler, since there is no wait keyword for re-joining.
Please help!
If you goal is to poll the server every second you have a number of problem.
There is no loop. You execute the method once and then stop.
You create a task using Delay and then ignore it. You ought to be creating a continuation of that task to do the rest of the work to actually not do anything for a second.
Here is an implementation that addresses those issues:
private async Task StartContinuousThread(CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
await Task.Run(() => CallServer());
await Task.Delay(1000, token);
}
}
Another possibility, especially if you're using an older version of C#, would be to use a timer to run some code every second.
As for updating the UI; you can do so freely anywhere outside of the call to Task.Run in this example. In your example you'd need to use some mechanism to marshal back to the UI thread, such as capturing the UI's synchronization context and posting to it.

Notify when thread is complete, without locking calling thread

I am working on a legacy application that is built on top of NET 3.5. This is a constraint that I can't change.
I need to execute a second thread to run a long running task without locking the UI. When the thread is complete, somehow I need to execute a Callback.
Right now I tried this pseudo-code:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
_thread.Join();
// execute finalizer
The second option, which does not lock the UI, is the following:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
while(_thread.IsAlive)
{
Application.DoEvents();
Thread.Sleep(100);
}
// execute finalizer
Of course the second solution is not good cause it overcharge the UI.
What is the correct way to execute a callback when a _thread is complete? Also, how do I know if the thread was cancelled or aborted?
*Note: * I can't use the BackgroundWorker and I can't use the Async library, I need to work with the native thread class.
There are two slightly different kinds of requirement here:
Execute a callback once the long-running task has completed
Execute a callback once the thread in which the long-running task was running has completed.
If you're happy with the first of these, the simplest approach is to create a compound task of "the original long-running task, and the callback", basically. You can even do this just using the way that multicast delegates work:
ThreadStart starter = myLongRunningTask;
starter += () => {
// Do what you want in the callback
};
Thread thread = new Thread(starter) { IsBackground = true };
thread.Start();
That's very vanilla, and the callback won't be fired if the thread is aborted or throws an exception. You could wrap it up in a class with either multiple callbacks, or a callback which specifies the status (aborted, threw an exception etc) and handles that by wrapping the original delegate, calling it in a method with a try/catch block and executing the callback appropriately.
Unless you take any special action, the callback will be executed in the background thread, so you'll need to use Control.BeginInvoke (or whatever) to marshal back to the UI thread.
I absolutely understand your requirements, but you've missed one crucial thing: do you really need to wait for the end of that thread synchronously? Or maybe you just need to execute the "finalizer" after thread's end is detected?
In the latter case, simply wrap the call to myLongRunningTask into another method:
void surrogateThreadRoutine() {
// try{ ..
mytask();
// finally { ..
..all 'finalization'.. or i.e. raising some Event that you'll handle elsewhere
}
and use it as the thread's routine. That way, you'll know that the finalization will occur at the thread's and, just after the end of the actual job.
However, of course, if you're with some UI or other schedulers, the "finalization" will now run on yours thread, not on the "normal threads" of your UI or comms framework. You will need to ensure that all resources are external to your thread-task are properly guarded or synchronized, or else you'll probably clash with other application threads.
For instance, in WinForms, before you touch any UI things from the finalizer, you will need the Control.InvokeRequired (surely=true) and Control.BeginInvoke/Invoke to bounce the context back to the UI thread.
For instance, in WPF, before you touch any UI things from the finalizer, you will need the Dispatcher.BeginInvoke..
Or, if the clash could occur with any threads you control, simple proper lock() could be enough. etc.
You can use a combination of custom event and the use of BeginInvoke:
public event EventHandler MyLongRunningTaskEvent;
private void StartMyLongRunningTask() {
MyLongRunningTaskEvent += myLongRunningTaskIsDone;
Thread _thread = new Thread(myLongRunningTask) { IsBackground = true };
_thread.Start();
label.Text = "Running...";
}
private void myLongRunningTaskIsDone(object sender, EventArgs arg)
{
label.Text = "Done!";
}
private void myLongRunningTask()
{
try
{
// Do my long task...
}
finally
{
this.BeginInvoke(Foo, this, EventArgs.Empty);
}
}
I checked, it's work under .NET 3.5
You could use the Observer Pattern, take a look here:
http://www.dofactory.com/Patterns/PatternObserver.aspx
The observer pattern will allow you, to notify other objects which were previously defined as observer.
A very simple thread of execution with completion callback
This does not need to run in a mono behavior and is simply used for convenience
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class ThreadTest : MonoBehaviour
{
private List<int> numbers = null;
private void Start()
{
Debug.Log("1. Call thread task");
StartMyLongRunningTask();
Debug.Log("2. Do something else");
}
private void StartMyLongRunningTask()
{
numbers = new List<int>();
ThreadStart starter = myLongRunningTask;
starter += () =>
{
myLongRunningTaskDone();
};
Thread _thread = new Thread(starter) { IsBackground = true };
_thread.Start();
}
private void myLongRunningTaskDone()
{
Debug.Log("3. Task callback result");
foreach (int num in numbers)
Debug.Log(num);
}
private void myLongRunningTask()
{
for (int i = 0; i < 10; i++)
{
numbers.Add(i);
Thread.Sleep(1000);
}
}
}
Try to use ManualRestEvent to signal of thread complete.
Maybe using conditional variables and mutex, or some functions like wait(), signal(), maybe timed wait() to not block main thread infinitely.
In C# this will be:
void Notify()
{
lock (syncPrimitive)
{
Monitor.Pulse(syncPrimitive);
}
}
void RunLoop()
{
for (;;)
{
// do work here...
lock (syncPrimitive)
{
Monitor.Wait(syncPrimitive);
}
}
}
more on that here:
Condition Variables C#/.NET
It is the concept of Monitor object in C#, you also have version that enables to set timeout
public static bool Wait(
object obj,
TimeSpan timeout
)
more on that here:
https://msdn.microsoft.com/en-us/library/system.threading.monitor_methods(v=vs.110).aspx

How to correctly dispose a Form, without risk of an Invoke being called from another thread on a disposed object?

I have a Form which "listens" to events that are raised elsewhere (not on the Form itself, nor one of its child controls). Events are raised by objects which exist even after the Form is disposed, and may be raised in threads other than the one on which the Form handle was created, meaning I need to do an Invoke in the event handler (to show the change on the form, for example).
In the Dispose(bool) method of the form (overridden) I unsubscribed from all events that may still be subscribed when this method is called. However, Invoke is still called sometimes from one of the event handlers. I assume this is because the event handler gets called just a moment before the event is unsubscribed, then OS switches control to the dispose method which executes, and then returns control back to the handler which calls the Invoke method on a disposed object.
Locking the threads doesn't help because a call to Invoke will lock the calling thread until main thread processes the invoked method. This may never happen, because the main thread itself may be waiting for a release of the lock on the object that the Invoke-calling thread has taken, thus creating a deadlock.
So, in short, how do I correctly dispose of a Form, when it is subscribed to external events, which may be raised in different threads?
Here's how some key methods look at the moment. This approach is suffering the problems I described above, but I'm not sure how to correct them.
This is an event handler handling a change of Data part of the model:
private void updateData()
{
if (model != null && model.Data != null)
{
model.Data.SomeDataChanged -= new MyEventHandler(updateSomeData);
model.Data.SomeDataChanged += new MyEventHandler(updateSomeData);
}
updateSomeData();
}
This is an event handler which must make changes to the view:
private void updateSomeData()
{
if (this.InvokeRequired) this.myInvoke(new MethodInvoker(updateSomeData));
else
{
// do the necessary changes
}
}
And the myInvoke method:
private object myInvoke(Delegate method)
{
object res = null;
lock (lockObject)
{
if (!this.IsDisposed) res = this.Invoke(method);
}
return res;
}
My override of the Dispose(bool) method:
protected override void Dispose(bool disposing)
{
lock (lockObject)
{
if (disposing)
{
if (model != null)
{
if (model.Data != null)
{
model.Data.SomeDataChanged -= new MyEventHandler(updateSomeData);
}
// unsubscribe other events, omitted for brevity
}
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
}
Update (as per Alan's request):
I never explicitly call the Dispose method, I let that be done by the framework. The deadlock has so far only happened when the application is closed. Before I did the locking I sometimes got some exceptions thrown when a form was simply closed.
There are two approaches to consider. One is to have a locking object within the Form, and have the internal calls to Dispose and BeginInvoke calls occur within the lock; since neither Dispose nor BeginInvoke should take very long, code should never have to wait long for the lock.
The other approach is to just declare that because of design mistakes in Control.BeginInvoke/Form.BeginInvoke, those methods will sometimes throw an exception that cannot practically be prevented and should simply be swallowed in cases where it won't really matter whether or not the action occurs on a form which has been disposed anyway.
I'd like to provide a sort of addendum to supercat's answer that may be interesting.
Begin by making a CountdownEvent (we'll call it _invoke_counter) with an initial count of 1. This should be a member variable of the form (or control) itself:
private readonly CountdownEvent _invoke_counter = new CountdownEvent(1);
Wrap each use of Invoke/BeginInvoke as follows:
if(_invoke_counter.TryAddCount())
{
try
{
//code using Invoke/BeginInvoke goes here
}
finally { _invoke_counter.Signal(); }
}
Then in your Dispose you can do:
_invoke_counter.Signal();
_invoke_counter.Wait();
This also allows you to do a few other nice things. The CountdownEvent.Wait() function has an overload with a timeout. Perhaps you only want to wait a certain period of time to let the invoking functions finish before letting them die. You could also do something like Wait(100) in a loop with a DoEvents() to keep things responsive if you expect the Invokes to take a long time to finish. There's a lot of niftyness you can achieve with this method.
This should prevent any weird timing race condition type of issues and it's fairly simple to understand and implement. If anyone sees any glaring problems with this, I'd love to hear about them because I use this method in production software.
IMPORTANT: Make sure that the disposal code is on the Finalizer's thread (which it should be in a "natural" disposal). If you try to manually call the Dispose() method from the UI thread, it will deadlock because it will get stuck on the _invoke_counter.Wait(); and the Invokes won't run, etc.
I had the problem with the Invoke method while multithreading, and I found a solution that works like a charm!
I wanted to create a loop in a task that update a label on a form to do monitoring.
But when I closed the form window, my Invoke threw an exception because my Form is disposed !
Here is the pattern I implemented to resolve this problem:
class yourClass : Form
{
private bool isDisposed = false;
private CancellationTokenSource cts;
private bool stopTaskSignal = false;
public yourClass()
{
InitializeComponent();
this.FormClosing += (s, a) =>
{
cts.Cancel();
isDisposed = true;
if (!stopTaskSignal)
a.Cancel = true;
};
}
private void yourClass_Load(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task.Factory.StartNew(() =>
{
try
{
while (true)
{
if (token.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { methodToInvoke(); });
}
}
}
catch (OperationCanceledException ex)
{
this.Invoke((MethodInvoker)delegate { stopTaskSignalAndDispose(); });
}
}, token);
}
public void stopTaskSignalAndDispose()
{
stopTaskSignal = true;
this.Dispose();
}
public void methodToInvoke()
{
if (isDisposed) return;
label_in_form.Text = "text";
}
}
I execute methodToInvoke() in an invoke to update the label from the form's thread.
When I close the window, the FormClosing event is called. I take this opportunity to cancel the closing of the window (a.Cancel) and to call the Cancel method of the object Task to stop the thread.
I then access the ThrowIfCancellationRequested() method which throws an OperationCanceledException allowing, juste after, to exit the loop and complete the task.
The Invoke method sends a "Window message" in a Queue.
Microsoft says : « For each thread that creates a window, the operating system creates a queue for window messages. »
So I call another method that will now really close the window but this time by using the Invoke method to make sure that this message will be the last of the Queue!
And then I close the window with the Dispose() method.

What is the best way to thread work in c#?

What's the best way to thread work (methods) in c#?
For example:
Let's say I have a form and want to load data from db.
My form controls:
- dataGridView (to show data from DB),
- label (loading status) and
- button (start loading).
When I click the button my form is frozen until the task is done. Also the loading status does not change until task is done. I think async threading would be the answer?
So my question: what's the best way to handle this? I know there is a lot stuff about Threading, but what's the difference between them and how do you make it thread safe?
How do you solve this kind of problems?
Best Regards.
If using Windows Forms, you should look at BackrgroundWorker. More generally, it is often useful to use the ThreadPool class. And finally, it is worth to take a look at the new .NET 4's Parallel class.
There is no universal 'best' way to thread work. You just have to try different ways of doing things, I'm afraid.
I particularly like Jeremy D. Miller's continuation idea described at this page (scroll down to find the "continuations" section). It's really elegant and means writing very little boilerplate code.
Basically, when you call "ExecuteWithContinuation" with a Func argument, the function is executed asynchronously, then returns an action when it finishes. The action is then marshalled back onto your UI thread to act as a continuation. This allows you to quickly split your operations into two bits:
Perform long running operation that shouldn't block the UI
... when finished, update the UI on the UI thread
It takes a bit of getting used to, but it's pretty cool.
public class AsyncCommandExecutor : ICommandExecutor
{
private readonly SynchronizationContext m_context;
public AsyncCommandExecutor(SynchronizationContext context)
{
if (context == null) throw new ArgumentNullException("context");
m_context = context;
}
public void Execute(Action command)
{
ThreadPool.QueueUserWorkItem(o => command());
}
public void ExecuteWithContinuation(Func<Action> command)
{
ThreadPool.QueueUserWorkItem(o =>
{
var continuation = command();
m_context.Send(x => continuation(), null);
});
}
}
You'd then use it like this (forgive the formatting...)
public void DoSomethingThatTakesAgesAndNeedsToUpdateUiWhenFinished()
{
DisableUi();
m_commandExecutor.ExecuteWithContinuation(
() =>
{
// this is the long-running bit
ConnectToServer();
// This is the continuation that will be run
// on the UI thread
return () =>
{
EnableUi();
};
});
}
You can use this kind of pattern:-
private void RefreshButton_Click(object sender, EventArgs e)
{
MessageLabel.Text = "Working...";
RefreshButton.Enabled = false;
ThreadPool.QueueUserWorkItem(delegate(object state)
{
// do work here
// e.g.
object datasource = GetData();
this.Invoke((Action<object>)delegate(object obj)
{
// gridview should also be accessed in UI thread
// e.g.
MyGridView.DataSource = obj;
MessageLabel.Text = "Done.";
RefreshButton.Enabled = true;
}, datasource);
});
}
You cannot access your controls from the code that runs in the spun-off thread - the framework does not allow this, which explains the error you are getting.
You need to cache the data retrieved from the db in a non-forms object and populate your UI with data from that object after the background worker thread is done (and handle synchronization for access to that object).

Categories