Making comparision in one thread between values from another thread C# - c#

I want to use BackgroundWorker in my application. And I've learned, that when I want to do this:
buttonStart.Enabled = false;
in main thread, with another thread I should do it like this:
if (buttonStart.InvokeRequired) { buttonStart.Invoke(new Action(() => buttonStart.Enabled = false)); }
else buttonStart.Enabled = false;
But when it goes to comparision operations:
if(tabControlDbSwitch.SelectedIndex == 0)
it doesn't works.
So, here is my question:
if ((!tabControlDbSwitch.InvokeRequired && tabControlDbSwitch.SelectedIndex == 0) ||
(tabControlDbSwitch.InvokeRequired && /*What should I write here?*/))
And maybe you've got some hints for me, 'cause I'm totally newbie in multi threading, but I want to learn it as fast as possible.
I.e. I've heard that sometimes it will be better to use BeginInvoke than Invoke, but I don't know why and when.

CheckSelection is the function that you invoke from the function where this if code was return
public void CheckSelection()
{
if (tabControlDbSwitch.InvokeRequired)
{
tabControlDbSwitch.Invoke(new Action(() => { CheckTabSelection(); }));
}
else
CheckTabSelection();
}
public void CheckTabSelection()
{
if (tabControlDbSwitch.SelectedIndex == 0)
{
// Do my work .....
}
}
You said you have heard that sometimes it will be better to use BeginInvoke than Invoke, but I don't know why and when. invoke and begin invoke are of two types delegate and control. In your example you are using Contol.Invoke
Delegate.Invoke: Executes synchronously, on the same thread.
Delegate.BeginInvoke: Executes asynchronously, on a threadpool thread means the function that is invoked in begin invoke will be executed on a new thread from a thread pool and you can continue doing your operation on same thread (Parallel execution).
Control.Invoke: Executes on the UI thread, but calling thread will wait for completion of the invoked function before continuing.
Control.BeginInvoke: Executes on the UI thread, and calling thread will not wait for completion of invoked function.
Yes it is advisable that we use Control.BeginInvoke rather then Control.Invoke as you don't have to worry about deadlocks.
For example, if you remove the code
if(tabControlDbSwitch.InvokeRequired)
and always use
tabControlDbSwitch.Invoke(new Action(() => { CheckTabSelection(); }));
and in some case this function is invoked from UI main thread then your code will hang and result in deadlock.

Here's another approach that actually allows the Invoke() to RETURN a value.
This way your code flows a little better:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (GetSelectedIndex(this.tabControlDbSwitch) == 0)
{
Console.WriteLine("Success!");
}
}
private delegate int ReturnSelectedIndex(TabControl tb);
private int GetSelectedIndex(TabControl tb)
{
if (tb.InvokeRequired)
{
return (int)tb.Invoke(new ReturnSelectedIndex(GetSelectedIndex), new Object[] { tb });
}
else
{
return tb.SelectedIndex;
}
}

Related

Callback for task, why does the UI thread block

I have the following piece of code:
public static async Task<SqlConnection> OpenSqlConnectionAsync()
{
if (_SqlConnection == default(SqlConnection))
{
_SqlConnection = new SqlConnection();
}
if (_SqlConnection.State == ConnectionState.Closed || _SqlConnection.State == ConnectionState.Broken)
{
_SqlConnection.ConnectionString = SqlConnectionStuff.GetConnectionString;
Task ConnectionTask = _SqlConnection.OpenAsync();
await ConnectionTask.ContinueWith((PreviousTask) =>
{
}
);
if (_SqlConnection.State == ConnectionState.Open)
{
MainWindow.Instance.lblCursorPosition.Dispatcher.Invoke(() => { MainWindow.Instance.lblCursorPosition.Text = "Connection opened!"; });
}
else
{
MainWindow.Instance.lblCursorPosition.Dispatcher.Invoke(() => { MainWindow.Instance.lblCursorPosition.Text = "Connection not opened!"; });
}
}
return GetSqlConnection;
}
In a separate class with the hopefully describing name SqlConnectionStuff... (no worries it will get changed soon ;P)
And down in my Window code there's is written the following:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
SqlConnectionStuff.OpenSqlConnectionAsync().Wait();
}
So when Invoking this using the Wait method behind the Task, stops the execution at the ContinueWith callback # the OpenSqlConnectionAsync method.
The window freezes. It doesn't seem to finish and it looks like the UI thread is getting blocked, which makes sense from my rudimentary insights into the behaviour of the threads. It is not necessary for it to block at all but this method has to be executed before anything else will work so it won't matter at all if the user input is locked as long as the connection is established.
My interest now would be, why if I remove the Wait() instruction, the await on the callback seems to be executed flawlessly without getting stuck (as it is an empty instruction which can't fail obv.), and afterwards the information for the user is displayed in the UI.
This code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
SqlConnectionStuff.OpenSqlConnectionAsync().Wait();
}
...specifically the Wait() blocks the UI thread from executing. By the way, calling an async method then explicitly blocking on it by calling Wait defeats the purpose of async/await by the way. It's like spinning up a thread only to Join on it. There are times when its ok to do so like when the signature of the method can't be changed to async (as in console apps Main methods prior to C# 7)
Meanwhile the following code attempts to synchonously thread marshal from whatever is the current thread to the UI thread in order to have the UI thread update the lblCursorPosition.Text property.
MainWindow.Instance.lblCursorPosition.Dispatcher.Invoke(() =>
{ MainWindow.Instance.lblCursorPosition.Text = "Connection opened!"; });
Unforunately as we already mentioned, the UI thread is already busy waiting for OpenSqlConnectionAsync to complete. So now you have a case of both ends waiting on the other. You have a deadlock.
A fix would be to change the method signature like so and call await:
private async void Window_Loaded(object sender, RoutedEventArgs e) // <-- note async
{
// await synchronously
await SqlConnectionStuff.OpenSqlConnectionAsync(); // await here. No Wait()
}
You could fix it another way by changing Invoke to BeginInvoke. The latter posts the action asynchronously to the UI thread. The net effect would be OpenSqlConnectionAsync would return the GetSqlConnection; the UI thread would resume following the Wait(); and later process the updating of the Label.
MainWindow.Instance.lblCursorPosition.Dispatcher.BeginInvoke(() =>
{ MainWindow.Instance.lblCursorPosition.Text = "Connection opened!"; });

InvokeRequired=true but BeginInvoke fails causing freeze

C# windows forms VS 2013 OS:Win7
I am having an interesting problem where invokeRequired is true but when I call beginInvoke() it never executes and the window never closes.
However when I remove beingInvoke() altogether the window closes ok.
public void CloseMyForm()
{
//if I remove this if block altogether including beingInvoke() the window closes ok
if ( !this.IsDisposed && this.InvokeRequired && this.IsHandleCreated )
{
log("callin begininvoke()"); //this is logged correctly
this.BeginInvoke((MethodInvoker)delegate() { CloseMyForm(); });
return;
}
log("outside of begin invoke"); //this is never logged
this.Close();
}
CloseMyForm is called by a separate thread which is created like this at the startup. Please note this is not the main window but a separate window open from the main form.
Thread connectThread = new Thread(new ThreadStart(CheckWhenToCloseMyForm));
public void CheckWhenToCloseMyForm()
{
while (true)
{
CallSomeFunc();
CallSomeFunc1();
if (allconditionsmet)
{
System.Threading.Thread.Sleep(1000);
CloseMyForm();
break;
}
}
}
The BeginInvoke is made available via the base Control class.
Executes a delegate asynchronously on the thread that the control's underlying handle was created on
If the InvokedRequired property is actually true, that means "the caller must call an invoke method when making method calls to the control because the caller is on a different thread than the one the control was created on".
It looks like you're incorrectly calling BeginInvoke, you should try calling Invoke instead.
Executes the specified delegate on the thread that owns the control's underlying window handle
public void CloseMyForm()
{
if (!this.IsDisposed && this.InvokeRequired && this.IsHandleCreated)
{
log("calling invoke()");
this.Invoke((MethodInvoker)delegate() { CloseMyForm(); });
}
else
{
log("outside of invoke"); // this is never logged
this.Close();
}
}
Check out this neat little extension method that could help simplify this. With this you could write your close method like this instead.
public void CloseMyForm()
{
this.ThreadSafeInvoke(() => this.Close());
}
Okay, now that you have provided this snippet I understand the issue.
Thread connectThread = new Thread(new ThreadStart(CheckWhenToCloseMyForm));
public void CheckWhenToCloseMyForm()
{
while (true)
{
CallSomeFunc();
CallSomeFunc1();
if (allconditionsmet)
{
System.Threading.Thread.Sleep(1000);
CloseMyForm()
}
}
}
In your while loop you need to break or return after you invoke CloseMyForm. That's it...very simple. You can use either BeginInvoke or Invoke.

C# Wait delegate finish before continue

I need to access a DataGridView control from a a thread other than the thread it was created on. I read I must use a delegate and it works, but I need to wait that delegate finishes before continue in the thread. I tried to call EndInvoke after BeginInvoke, but the thread continues.
public void ArrangeGrid()
{
ArrangeGridHandler ag = ArrangeGridAsync;
IAsyncResult result = ag.BeginInvoke(cb, null);
ag.EndInvoke(result);
}
When I call ArrangeGrid() the thread continues even if it isn't finished. How can I do?
Thanks!
when using an Async method a new thread will be created for you.
Try to use Invoke
public void ArrangeGrid()
{
if(this.InvokeRequired)
{
Action arrange = ArrangeGrid ;
this.Invoke(arrange);
}
else
{
//insert your code here
}
}

Dispatcher.Invoke from a new thread is locking my UI

i'm using wpf, there's a button on my ui.
when the user clicks it, i have a for loop that runs a new method, on a new thread using autoresetevent.
in that method on that new thread, i'm using a label, let's call it lblStatus. i want to update that label on this thread that's not on the ui. using wpf, i have to use Dispatcher.Invoke.
here's a sample of my code:
Thread thread= new Thread(StartLooking);
thread.Start();
_waitHandle.WaitOne();
private void StartLooking(object value)
{
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread)
{
lblStatus.Content = "Scanning>...";
}
else
{
lblStatus.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => lblStatus.Content = "Scanning>>>>>"));
}
_waitHandle.Set();
}
the program just stops here. it doesn't change the content of the label, it returns to my ui, but blocks it.
i've tried
lblStatus.Dispatcher.Invoke(DispatcherPriority.Normal, new LblStatusThreadCheck(lblStatusThreadCheck), "Scanning...");
as well, but that isn't working also. any ideas?
The problem is that you're making it impossible for this to execute, since you're using Invoke.
Dispatcher.Invoke will not return until the UI thread processes. However, you've blocked the UI thread by calling _waitHandle.WaitOne();, and don't set the wait handle until AFTER this processes. The two effectively cause a dead lock.
If you switch this to use BeginInvoke instead, the UI will queue the element, the wait handle will set, THEN the label will update. It will work and not block, however.
Since the two previous posts already cover the problem in your code, just a suggestion: instead of
if (lblStatus.Dispatcher.Thread == Thread.CurrentThread)
try using
if (!lblStatus.CheckAccess())
It's cleaner and has the exact intent you want. Just read about it here.
You probably want to use BeginInvoke instead. Invoke will block the thread that called it until the UI thread has run the Action, and since you're setting the priority to Background, this could take some time.
Best solution I have found for .net 4.5+ is using SynchronizationContext Post
Example (Task.Run's can be as many as you want in parallel accessing UI):
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var context = SynchronizationContext.Current;
Task.Run(() =>
{
var i = 0;
while (true)
{
context.Post((tmp) =>
{
uiText.Text = $"{i}";
}), this);
Thread.Sleep(1000);
i++;
}
});
}

c# Thread issue using Invoke from a background thread

I've got thread, which processes some analytic work.
private static void ThreadProc(object obj)
{
var grid = (DataGridView)obj;
foreach (DataGridViewRow row in grid.Rows)
{
if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString()) != null)
UpdateGridSafe(grid,row.Index,1);
Thread.Sleep(10);
}
}
I want safely update my gridView at loop, so I use classic way:
private delegate void UpdateGridDelegate(DataGridView grid, int rowIdx, int type);
public static void UpdateGridSafe(DataGridView grid, int rowIdx, int type)
{
if (grid.InvokeRequired)
{
grid.Invoke(new UpdateGridDelegate(UpdateGridSafe), new object[] { grid, rowIdx, type });
}
else
{
if (type == 1)
grid.Rows[rowIdx].Cells["Prep"].Style.ForeColor = Color.Red;
if (type==2)
grid.Rows[rowIdx].Cells["Prep"].Style.ForeColor = Color.ForestGreen;
}
}
But when I enter UpdateGridSafe, the program hangs.
In the debugger, I see that grid.Invoke doesn't invoke UpdateGridSafe. Please help - what's wrong?
EDIT
Classic thread create code
Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
t.Start(dgvSource);
t.Join();
MessageBox.Show("Done", "Info");
You have a deadlock. Your t.Join is blocking the GUI thread until ThreadProc is done. ThreadProc is blocked waiting for t.Join to finish so it can do the Invokes.
Bad Code
Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
t.Start(dgvSource);
t.Join(); <--- DEADLOCK YOUR PROGRAM
MessageBox.Show("Done", "Info");
Good Code
backgroundWorker1.RunWorkerAsync
private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
var grid = (DataGridView)obj;
foreach (DataGridViewRow row in grid.Rows)
{
if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString()) != null)
UpdateGridSafe(grid,row.Index,1);
// don't need this Thread.Sleep(10);
}
}
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done", "Info");
}
EDIT
Also use BeginInvoke instead of Invoke. That way your worker thread doesn't have to block every time you update the GUI.
Reference
Avoid Invoke(), prefer BeginInvoke()
It's because you're joining on your worker thread. Your UI thread starts the background thread, then calls Join on it. This stops the UI thread from performing any other actions.
During this, the background thread is doing its work and calling Invoke, which waits for the UI thread to respond. Because the UI thread is waiting for a Join, it won't ever process the request to invoke. Hence, deadlock.
What you should do, is eliminate the Join and the MessageBox. Put the MessageBox into its own function.
void NotifyDone() {
if( InvokeRequired ) BeginInvoke( (MethodInvoker) NotifyDone );
else {
// Perform any post-processing work
MessageBox.Show("Done", "Info");
}
}
When the background thread is done, simply call this method (and eliminate static from ThreadProc).
private void ThreadProc(object obj)
{
var grid = (DataGridView)obj;
foreach (DataGridViewRow row in grid.Rows)
{
if (Parser.GetPreparationByClientNameForSynonims(row.Cells["Prep"].Value.ToString()) != null)
UpdateGridSafe(grid,row.Index,1);
Thread.Sleep(10);
}
NotifyDone();
}
And like everyone else has already said, the use of Sleep, especially at such a low interval is either dangerous, misleading or worthless. I'm in the count it worthless camp.
The Invoke statement will wait until the main thread's message pump isn't busy, and can handle a new message. If your main thread is busy, the Invoke will hang.
In your case, it looks like your top code is running in a tight loop, so there's never a chance for the Invoke in the bottom code to actually run. If you change the Thread.Sleep in your upper code block to something with a time in it, hopefully that will give your main thread a chance to handle the .Invoke call.
Depending on what your main application thread is doing, you may need to actually finish your first loop before any of the .Invoke calls will run - if that's the case, I can post some modified code that might work better.
Never, ever, every use Thread.Sleep(0). It doesn't do what you think it does and will cause you nothing but pain. For example, in a tight loop the OS may decide that the thread that just slept is the next one to run. As a result you won't actually yield the thread.
Try your code again using Thread.Sleep(1) every N iterations where N is about 0.25 to 1.0 seconds worth of work.
If that doesn't work let me know and we can look at how ThreadProc is created.
References
Never Sleep(0) in an Infinite Loop
EDIT
Argument for never using Thread.Sleep
Thread.Sleep is a sign of a poorly designed program.
You also could be having issues accessing the grid at the same time from different threads. DataTables are not thread safe, so I'd guess that DataGridView isn't either. Here's some sample code from this article on DataRow and Concurrency where you would use Monitor.Enter and Montori.Exit to get some concurrency in place.
public void DoWorkUpdatingRow(object state)
{
List<DataRow> rowsToWorkOn = (List<DataRow>)state;
foreach (DataRow dr in rowsToWorkOn)
{
Monitor.Enter(this);
try
{
dr["value"] = dr["id"] + " new value";
}
finally
{
Monitor.Exit(this);
}
}
}

Categories

Resources