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" ;)
Related
I want to access label1 but I can't since it's not static.
Also, I can change neither functions to non-static because I need them in the thread. Is there any way to access non-static label1 from static functions?
Set label1 to static? Or is there any way that I can change the functions to non-static and still use it for threads?
PS. In this sample code, it just sets the label's text as "Access Denied" but in my actual code, SetDataStore method will constantly read changing values from a c++ shared memory and keep updating the label's text.
public partial class Form1 : Form
{
Thread testThread = new Thread(TestFunction);
public Form1()
{
InitializeComponent();
testThread.Start();
}
static void TestFunction()
{
SetDataStore();
}
static void SetDataStore()
{
// can't access non-static control
label1.Text = "Access Denied";
}
}
I think there is a significant lack of understanding of threads and thread safety.
While static methods are by convention thread safe, they do not automatically become so just by being static. You need to ensure they are thread safe. There should be no problem starting a thread at a regular non static member method, but you still need ensure it is safe.
But you are writing an UI program, and accessing UI objects from any thread except the UI thread is illegal. So there is no way to do what your example tries to do.
The correct way would be to move any CPU heavy work to a background thread, and update the UI on the UI thread. For example:
public async void OnButtonpress(...){
try{
var result = await Task.Run(OnBackgroundThread);
label1.Text = result ; // Update UI on UI thread
}
catch{
// handle exceptions
}
}
private string OnBackgroundThread(){
// Do CPU heavy work on background thread
return "Access Denied";
}
I think the problem you're trying to solve is to perform a long running process without blocking your UI and trying to manually kick off a thread that makes use of static methods to do this is the wrong tool. Even if you make your label available to your static method, you'll still need to queue the work on the UI component with InvokeRequired and BeginInvoke etc.
A much better approach is to make use of the Task Asynchronous Pattern. Your form could then look something like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
label1.Text = "Loading ...";
}
private async void Form1_Load(object sender, EventArgs e)
{
await SetDataStoreAsync();
}
private async Task SetDataStoreAsync()
{
string result = "";
// await your awaitable process here
await Task.Delay(1000);
// If your process isn't awaitable, try make it so.
// If you can't here's a quick way to place your work on a worker thread and await it.
await Task.Run(() =>
{
System.Threading.Thread.Sleep(5000);
result = "Access denied";
});
label1.Text = result;
}
}
This question already has answers here:
Where is the WPF Timer control?
(4 answers)
Closed 4 years ago.
How can I create an async structure that will be consist of stack of delegates and popping them and invoke each of them every N ms?
The problem is now I have lot delegates that invoke changes on ui and it causes ui freezing so how to make this delegates invoking every N ms if stack is not empty.
Now I have this
class CallbackRestriction
{
private Stack<KeyValuePair<Action<ImageWrapper>, ImageWrapper>> _callbackList =
new Stack<KeyValuePair<Action<ImageWrapper>, ImageWrapper>>();
public void AddCallback(Action<ImageWrapper> action, ImageWrapper payload)
{
_callbackList.Push(new KeyValuePair<Action<ImageWrapper>, ImageWrapper>(action, payload));
}
private async Task CallbackEmitLoop()
{
while (true)
{
await Task.Delay(TimeSpan.FromMilliseconds(20));
try
{
var callback = _callbackList.Pop();
callback.Key.Invoke(callback.Value);
}
catch (Exception e)
{
await Task.Delay(200);
}
}
}
}
But how can I make CallbackEmitLoop start in the background? Or any other solution for this?
Update 1
I do not need the dispather timer because is tighten with wpf and maybe for "timer" things I should use synchronization context. And I don't have problems with calling to my collection from others context because collection can be made concurrency ready. I need something like a valve that would restrict invoking delegates once they have been added. So how I described problem above I can get a lot of "updates"(delegates) at one time and if I just apply them(call delegates) the ui thread would be busy significant time that will cause freezing and because of this I somehow should keep times before apply next "update".
Here's one way. The code below uses your CallbackRestriction class and my dummy implementation of ImageWrapper. I've made the CallbackEmitLoop method public so that my window can start it with Task.Run.
Because I maintain the delegate emitter instance in my window, it will run as long as the window is alive. A real app would likely run it from some other service class.
The callback needs to use Dispatcher to invoke code on the UI thread if it needs to work with WPF UI elements because the Task runs on a thread pool thread, and any delegate invocations will run on that thread too.
Regarding the comment that this may be a duplication question, the OP is asking how to have a running Task invoke delegates that interact with the UI, and while DispatcherTimer is certainly a reasonable approach, it doesn't address the OP's question, nor does it offer an explanation as to why DispatcherTimer would be a more appropriate implementation.
// My dummy ImageWrapper
public class ImageWrapper
{
public string Val { get; set; }
}
public partial class MainWindow
{
private CallbackRestriction _restriction = new CallbackRestriction();
public MainWindow()
{
InitializeComponent();
_restriction.AddCallback(MyCallback, new ImageWrapper() {Val = "Hello"});
Task.Run(_restriction.CallbackEmitLoop);
}
private void MyCallback(ImageWrapper wrapper)
{
// since the callback will be running on the
// thread associated with the task, if you
// want to interact with the UI in the callback
// you need to use Dispatcher
Dispatcher.BeginInvoke(new Action(() =>
{
Debug.WriteLine(wrapper.Val);
}));
}
}
The UI can be passed information from an asynchronous task using IProgress or BackgroundWorker.ReportProgress:
class Approach1 : UserControl
{
enum Stage { INIT, STATUS, DATA, TIME, ... }
struct ProgressObject
{
int StatusCode;
int SecondsRemaining;
IList<int> Data;
Stage CurrentStage;
}
TextBox Status;
async Task DoWork1(IProgress<ProgressObject> progress)
{
await Task.Run( () =>
{
progress.Report(new ProgressObject(0, 0, null, Stage.INIT));
int code = DoSomething();
progress.Report(new ProgressObject(code, 0, null, Stage.STATUS));
IList<int> Data = ...;
progress.Report(new ProgressObject(0, 0, Data, Stage.DATA));
int Seconds = ...;
progress.Report(new ProgressObject(0, time, null, Stage.TIME));
});
}
void ReportProgress(ProgressObject progress)
{
switch (progress.CurrentStage)
{
case Stage.CODE:
Status.Text = DecodeStatus(progress.StatusCode);
break;
// And so forth...
}
}
async void Caller1(object sender, EventArgs e)
{
var progress = new Progress<ProgressObject>(ReportProgress);
await DoWork2(progress);
}
}
However, this can also be done by passing a delegate to a UI object's BeginInvoke method (Invoke if we want to block):
class Approach2 : UserControl
{
Textbox Status;
int StatusCode
{
set
{
BeginInvoke(new Action( () => Status.Text = DecodeStatus(value));
}
}
// Imagine several other properties/methods like the above:
int SecondsRemaining;
void UpdateData(IList<int> data);
async Task DoWork2()
{
await Task.Run( () =>
{
StatusCode = DoSomething();
UpdateData(...);
SecondsRemaining = ...;
});
}
async void Caller2(object sender, EventArgs e)
{
await DoWork1();
}
}
Should the dedicated progress reporting mechanisms be preferred over Invoke? If, so why? Are there any likely 'gotchas' arising from either approach?
IMHO, the Invoke way is simpler / requires less code compared to, say, a ReportProgress accepting a progress struct with several fields, especially if progress is reported at multiple stages of the task and the reporting method thus needs to branch to the appropriate reporting for a given stage.
You should have gotten a cue from your struggles to make Approach2 actually compile. Took a while, didn't it? I saw you repeatedly editing the snippet. Another cue you got was that the only way to get there was to derive your class from UserControl.
Which is the problem with Begin/Invoke(), it can only work when you have access to a Control object. Code inside a library often (and should) have no idea what the UI looks like. It might not even be implemented in Winforms, could be used in a WPF or Universal app for example.
Progress<> works with those GUI class libraries as well, it uses a more universal way to properly synchronize. Provided by the SynchronizationContext.Current property, it relies on the GUI class library to install a provider. The one that Winforms installs, WindowsFormsSynchronizationContext, automatically calls BeginInvoke() in its Post() method and Invoke() in its Send() method. Also the mechanism that makes async/await code independent from the UI implementation.
There is one disadvantage to Progress<>, it can completely fail to get the job done in a very hard to diagnose way. The object must be created by code that runs on the UI thread of an app. If it is not then SynchronizationContext.Current doesn't have a value and the ProgressChanged event is going to fire on an arbitrary threadpool thread. Kaboom if you try to update the UI with an event handler, you won't know why because the exception occurs in code that's far removed from the bug.
But sure, if you hardcode your class to derive from System.Windows.Forms.UserControl then you have little use for Progress<>. Other than the feel-good feeling that you'll have less work to do when you ever port it to another GUI class library.
I have 2 async processes that need to be called one after the other (one is an XML creation backgroundworker and the other is a raring BW that uses the XML files created in the first process). The main reason for these threads is to stop the UI freezing and provide a status update by the way of a progress bar - as such a synchronous approach is not desirable/possible.
if (!CreateXMLBW.IsBusy)
{
CreateXMLBW.RunWorkerAsync("");
}
if (!CreateRarBW.IsBusy)
{
CreateRarBW.RunWorkerAsync();
}
I cannot put the second BW inside the first's completion event as the processes can be used separately and as such if I just want to create the XML files I can do that.
I have tried using AutoResetEvent and WaitOne but this (for whatever reason) still doesn't work.
Are there any other ways I can wait for a BW to complete without freezing the main UI thread?
Your scenario is exactly what Task was designed for. In your particular case your code might look like this:
public delegate void UpdateUI(int progress);
private void RunOneAfterAnotherAsync()
{
Task<XmlElement> task = Task.Factory.StartNew<XmlElement>(CreateXMLBW);
task.ContinueWith(CreateRarBW);
}
private XmlElement CreateXMLBW()
{
// your code
// progress
progressBar1.Invoke((UpdateUI)UpdateProgressBar, new object[] {progressValue});
// result
XmlDocument doc = new XmlDocument();
return doc.CreateElement("element");
}
private void CreateRarBW(Task<XmlElement> task)
{
CreateRarBW(task.Result);
}
private void CreateRarBW(XmlElement arg)
{
// your code
}
public void UpdateProgressBar(int value)
{
this.progressBar1.Value = value;
}
RunOneAfterAnotherAsync is not blocking and your 2 methods run asynchronously one after another. CreateRarBW runs only if CreateXMLBW ends with no exception but you can change that by using additional arguments in ContinueWith.
You can do much more than this example shows - I encourage you to explore the Task class.
EDIT
I have extend the example a little bit to incorporate a result being passed from the first task into the second one. Also added UI progress example.
You could also use a Task like in this example:
class Program
{
static XElement CreateXml()
{
System.Threading.Thread.Sleep(1000);
return XElement.Parse(#"<FooBar>Hi!</FooBar>");
}
static void ProceedXml(XElement xml)
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine(xml.ToString());
}
public static void Main()
{
Task.Factory.StartNew<XElement>(CreateXml)
.ContinueWith(t => ProceedXml(t.Result));
Console.ReadKey();
}
}
If you don't want block UI till waiting for event (so I suppose you're gonna do something)
you can raise an event at the end of the DoWork(), and UI thread can recieve it.
If you're using 4.0 and can avoid of using BackgroundWorker, you can make use of Task.ContinueWith from TPL.
A pseudocode may look like this:
Action action =(() => DoWorkMethod());
Task.Factory.StartNew(() => action()).ContinueWith(()=>CallAfterComplete());
Your UI can handle the RunWorkerCompleted event on the first BW and invoke the second BW.
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).