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;
}
}
Related
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" ;)
UpDate1:
More detail: Thread 1 and 2 must be continuously active. Thread 1 is updating its GUI and doing HTTP POSTs. Thread 2 is using HTTPListener for incoming HTTP POSTs, and supplying that data to Thread 1. So the GUI needs to be display with current Textbox values and updated when Thread 2 supplies the data. Will Servy's or another approach allow both Threads to do their work concurrently? It appears the main thread waits for Thread 2 to complete it's work. It then takes the prepWork and does work with it. I coded in Servy's example but I couldn't find a definition for Run() with the Task class. It's library has no such method. I'm using Net 4.0 on VS 2010. Is there an equivalent method to use? Start() didn't compile either and I understand you can only run the Task once. Thanks for any additional assistance you can share.
Original Question:
I've tested code that will successfully kick off my event and update my GUI textbox in an event handler if the event is kicked off in what I understand as the UI Thread 1. When I attempt to call a Thread 1 method Fire() from my independent Thread 2 method PrepareDisplay(), Fire() is called and in turns fires off the event. I put in some Thread-safe call code (modeled from MSDN tutorial on Thread-Safety in WinForms), but the event handler still doesn't update the Textbox. When stepping thru the code, it appears that the InvokeRequired is false. My eventual goal is to pass data from Thread 2 to UI Thread 1 and update the Textboxes with the new data. I don't understand why the Thread-safe code isn't enabling this. Can someone help me understand this better, and what I have neglected? Below is the code:
Thank you very much,
namespace TstTxtBoxUpdate
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Aag_PrepDisplay aag_Prep1 = new Aag_PrepDisplay();
Thread AagPrepDisplayThread = new Thread(new ThreadStart(aag_Prep1.PrepareDisplay));
AagPrepDisplayThread.Start();
while(!AagPrepDisplayThread.IsAlive)
;
Thread.Sleep(1000);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SetOperation());
}
}
}
namespace TstTxtBoxUpdate
{
// Thread 1: UI
public partial class SetOperation : Form
{
private string text;
public event Action<object> OnChDet;
delegate void SetTextCallback(string text);
private Thread demoThread = null;
public SetOperation()
{
InitializeComponent();
OnChDet += chDetDisplayHandler;
}
public void FireEvent(Aag_PrepDisplay aagPrep)
{
OnChDet(mName);
}
private void chDetDisplayHandler(object name)
{
this.demoThread = new Thread(new ThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
private void ThreadProcSafe()
{
this.SetText("402.5");
}
private void SetText(string text)
{
if(this.actFreqChan1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.actFreqChan1.Text = text;
}
}
}
}
namespace TstTxtBoxUpdate
{
// Thread 2: Data prepare
public class Aag_PrepDisplay
{
#region Fields
private Aag_PrepDisplay mAagPrep;
#endregion Fields
#region Properties
public Aag_PrepDisplay AagPrepDisp;
public Aag_PrepDisplay AagPrep
{
get { return mAagPrep; }
set { mAagPrep = value; }
}
#endregion Properties
#region Methods
public void PrepareDisplay()
{
mAagPrep = new Aag_PrepDisplay();
SetOperation setOp1 = new SetOperation();
setOp1.FireEvent(mAagPrep); // calls Thread 1 method that will fire the event
}
#endregion Methods
}
}
You're getting to the point of calling InvokeRequired when your main thread is still on Thread.Sleep. It hasn't even gotten to the point of creating a message loop yet (which is one in Application.Run) so there is no message loop for Invoke to marshal a call to.
There are all sorts of issues here. You're creating multiple instance of your form, one that you show, and an entirely different form that you're setting the text of. You clearly did not intend to do this; you want to have a single form that you're setting the text for.
Your main thread should not be doing a busywait until your first thread finishes. It likely shouldn't be there at all. If it weren't for the fact that your new thread is creating yet another new thread, the fact that your main thread is blocking until the second thread finishes and the second thread is trying to marshall a call to the main thread, it would normally deadlock. You shouldn't really be creating a second new thread here at all, but this is a case of two bugs "cancelling each other out". It prevents the deadlock, but both are still incorrect, and inhibit your ability to get to a working solution.
You also shouldn't have the Thread.Sleep in the main thread at all. I have no idea what purpose that's trying to achieve.
If you're goal is simply to start some long running work before showing the first form and then to update that form when you have your results, you're doing way more work than you need to do.
To do this we can have our form accept a Task in its constructor representing the completion of the long running work. It can add a continuation to that task to set a label, or a textbox, or do...whatever, with the results of that Task.
public class SetOperation : Form
{
private Label label;
public SetOperation(Task<string> prepWork)
{
prepWork.ContinueWith(t =>
{
label.Text = t.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
Then the main thread simply needs to start a new Task to do the given work in a thread pool thread and pass that in to our form:
[STAThread]
static void Main()
{
Task<string> prepWork = Task.Run(() => DoWork());
Application.Run(new SetOperation(prepWork));
}
private static string DoWork()
{
Thread.Sleep(1000);//placeholder for real work
return "hi";
}
And we're done. Note that DoWork should probably be in its own class designed for handling your business logic; it probably shouldn't be stuck into the Program class.
References:
http://msdn.microsoft.com/en-us/library/ms171728.aspx
http://stackoverflow.com/questions/5408155/how-to-make-delegate-thread-sta
I wanted to create a new Thread and make it STA therefore I was not able to use asynchronous delegates or BackgroudWorker (as mentioned in references link 1) Therefore I end up creating a Thread of my own make it STA and attach a callback to know when the Task is complete. The code is something like below and even though I am using invoke required, I still get InvalidOperationException (once in a while)
delegate UpdateEventHander(Object sender, EventArgs e);
class MyTask{
// to generate an event
public event UpdateEventHandler Finished;
public void Start(){
Result = // something that require the thread to be STA.
Finished(this, EventArgs.Empty);
}
public Result GetResult(){
return Result;
}
}
Class Foo : Form{
// It has many UI Controls obviously
public void doSomething(){
MyTask task = new MyTask();
task.Finished += new UpdateEventHander(CompletionHandler);
Thread thread = new Thread(new ThreadStart(task.Start));
thread.setAppartmetnState(AppartmentState.STA);
thread.start();
}
public void CompletionHandler(Object sender, EventArgs e){
MyTask task = (MyTask) sender;
if (oneOfMyControls.InvokeRequired){
delegateToUpdateUIconrols del = new delegateToUpdateUIconrols(updateUIControls);
del.invoke();
}else{
UpdateUIControls();
}
}
public delegate void delegateToUpdateUIconrols();
public void UpdateUIControls(){
// It updates UI controls
// Datagrid view value properties like backgroud color and stuff.
// change text in the label.
}
}
Question 1: Which thread will UpdateUIControls execute ? - if you say "Main UI Thread" - then in that case how will the system know if its supposed to run in Main UI thead and NOT some OTHER thread? I am not passing any reference (about Main UI thread) when I call invoke() .. so invoke() is technically executed on the same thread..
Question 2: Once in a while, I get the InvalidOperationException. Exactly this one
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/6b450a21-e588-414a-afae-9adabfd03674/
If UpdateUIControls is executing in the main UI thread, there should be not prblem, Right? So, I guess answer to my question really depends upon question 1.
I will appreciate if someone share his/her wisdom on this
Karephul
Controls have thread-affinity; you can only safely talk to them from their creating thread.
You are checking InvokeRequired; however, you are mixing up Delegate.Invoke (runs on the current thread) with Control.Invoke (runs on the UI thread); very different meaning. It should be:
oneOfMyControls.Invoke(del [, args]);
I have a XAML application that serves as the UI for an automation. The entire automation can take anywhere from 20-30 hours to fully execute so I created a Task class object that essentially wraps Thread methods (Start/Stop/Reset).
However, when I run the automation method under the Task object, the XAML UI is busy and I cannot interact with the other controls, including the Pause button which toggles the Thread.Set() flag.
There is another post
Prevent UI from freezing without additional threads
where someone recommended the BackgroundWorker class this MSDN article mentions it is a bad idea to use this when if it manipulates objects in the UI, which mine does for purposes of displaying status counts:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Any idea around this?
private void OnButtonStartAutomationClick(object sender, RoutedEventArgs e)
{
btnPauseAutomation.IsEnabled = true;
Automation.Task AutomationThread = new Automation.Task(RunFullAutomation);
}
private void RunFullAutomation()
{
// do stuff that can take 20+ hours
// threaded so I can utilize a pause button (block)
}
class Task
{
private ManualResetEvent _shutdownFlag = new ManualResetEvent(false);
private ManualResetEvent _pauseFlag = new ManualResetEvent(true);
private Thread _thread;
private readonly Action _action;
public Task(Action action)
{
_action = action;
}
public void Start()
{
ThreadStart ts = new ThreadStart(DoDelegatedMethod);
_thread = new Thread(ts);
_thread.Start();
_thread.Priority = ThreadPriority.Lowest;
}
public void Resume()
{
_pauseFlag.Set();
}
public void Stop()
{
_shutdownFlag.Set();
_pauseFlag.Set();
_thread.Join();
}
private void DoDelegatedMethod()
{
do
{
_action();
}
while (!_shutdownFlag.WaitOne(0));
}
}
where someone recommended the BackgroundWorker class this MSDN article mentions it is a bad idea to use this when if it manipulates objects in the UI, which mine does for purposes of displaying status counts
BackgroundWorker is actually ideal for this, as it was designed for this type of scenario. The warning is that you shouldn't change UI elements inside of DoWork, but rather via ReportProgress and the ProgressChanged event.
The reason the warning exists is "DoWork" is executed on a background thread. If you set a UI element value from there, you'll get a cross threading exception. However, ReportProgress/ProgressChanged automatically marshals the call back into the proper SynchronizationContext for you.
Take a look at the Dispatcher object in WPF. You can, and should in your scenario, run the long running tasks on a background thread and the BackgroundWorker is a good way to do it. When you need to update the UI you need to verify access to the UI thread and if you don't have it use the dispatcher to invoke an update method on the UI thread.
There are two possible causes here: first, that the blocking task is blocking the UI thread rather than running on a background thread, and second, that the background thread is starving the UI thread so that it never gets the chance to respond to input. You need to find out which of these is the case. A crude way to do this is, in your Click handler, Debug.WriteLine the current thread ID (Thread.CurrentThread.ManagedThreadId), and do the same in the RunFullAutomation callback.
If these print the same number, then you have the first problem. Reed and TheZenker have provided solutions to this.
If these print different numbers, then you are already on a worker thread, and you have the second problem. (BackgroundWorker may get you to the worker thread more elegantly, and will help with updating the UI, but it won't stop starvation.) In this case the simplest fix is probably to set _thread.Priority = ThreadPriority.BelowNormal; before starting the worker thread.
By the way, your code never appears to actually call AutomationThread.Start, which means the RunFullAutomation callback isn't even executed. Is this just a typo?
I'd advise against rolling out your own Task class given that .NET 4 has full support for running tasks asynchronously in the background using the Task Parallel Library
That said,you can do what Reed suggests and use a BackgroundWorker which is ideal or if you prefer more control over the nature of how the task si executing, you could use the Task class from System.Threading.Tasks and implement something like so:
public partial class MainWindow : Window
{
CancellationTokenSource source = new CancellationTokenSource();
SynchronizationContext context = SynchronizationContext.Current;
Task task;
public MainWindow()
{
InitializeComponent();
}
private void DoWork()
{
for (int i = 0; i <= 100; i++)
{
Thread.Sleep(500); //simulate long running task
if (source.IsCancellationRequested)
{
context.Send((_) => labelPrg.Content = "Cancelled!!!", null);
break;
}
context.Send((_) => labelPrg.Content = prg.Value = prg.Value + 1, null);
}
}
private void Start_Click(object sender, RoutedEventArgs e)
{
task = Task.Factory.StartNew(DoWork, source.Token);
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
source.Cancel();
}
}
In DoWork() you use the WPF SynchronizationContext and post messages to update the UI wiget you need.
The example has a progress bar and a label control that is updated on each iteration of the for loop.Cancellation is supported using CancellationTokenSource which is checked in each iteration.
Hope this helps.
I have a windows forms program with a form MainForm. On a button press I start a code that runs (pulses) on every 0.5secs on another thread. I want to modify many things, like labels, progressbars on my MainForm, from the Pulse method. How is this possible?
So I would like to know, how to interract with variables, values, in that thread, and the MainForm. Modify each other, etc..
On foo button click, I tell my pulsator to start.
Pulsator.Initialize();
Here is the Pulsator class:
public static class Pulsator
{
private static Thread _worker;
public static void Initialize()
{
_worker = new Thread(Pulse);
_worker.IsBackground = true;
_worker.Start();
}
public static void Close()
{
if (_worker != null)
{
_worker.Abort();
while (_worker.IsAlive || _worker.ThreadState != ThreadState.Stopped)
{
//closing
}
}
}
public static void Pulse()
{
if (_worker != null)
{
while (true)
{
SomeOtherClass.Pulse();
Thread.Sleep(500);
}
}
else
{
SomeOtherClass.Pulse(); // yeah I know this doesnt needed
}
}
}
SomeOtherClass Pulse method looks like :
public static void Pulse()
{
//here I will have several values, variables, and I want to show results,
// values on my MainForm, like:
Random random = new Random();
MainForm.label1.Text = random.Next(123,321).ToString(); // I hope you know what I mean
}
Of course it's much complicated, it's just a silly example.
Generally, in WinForms it's not safe to modify the state of visual controls outside the thread that owns the control's underlying unmanaged resources (window handle). You have to use the Control.Invoke method to schedule executing the modification on the control's owning thread.
As others already mentioned, you have to use Control.Invoke to change the UI controls from the background thread.
Another option is to use System.ComponentModel.BackgroundWorker (it's available in the form designer toolbox). You could then take a regular forms timer, to call the RunWorkerAsync-Method and do your background work in the DoWork event handler, which is automatically called from another thread.
From there, you can hand data back to the main thread, by calling ReportProgress. This will raise the ProgressChanged event in the main thread, where you are free to update all your UI controls.
Why not use a System.Timers.Timer?
E.g.:
trainPassageTimer = new Timer(500);
trainPassageTimer.AutoReset = true;
trainPassageTimer.Elapsed += TimeElapsed;
...
private void TimeElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
// Do stuff
// Remember to use BeginInvoke or Invoke to access Windows.Forms controls
}
C# 2 or higher (VS2005) has anonymous delegates (and C# 3 has lambdas which are a slightly neater version of the same idea).
These allow a thread to be started with a function that can "see" variables in the surrounding scope. So there is no need to explicitly pass it anything. On the downside, there is the danger that the thread will accidentally depend on something that it should not (e.g. a variable that is changing in other threads).
_worker = new Thread(delegate
{
// can refer to variables in enclosing scope(s).
});