I have started a special course in multithreading but I have some fundamental issues I want to clear up. say I have a thread
Thread t1 = new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
IsCancel = false;
this.workProj.DoWorkWithRefSync(ref IsCancel);
});
t1.Start();
Followed by
while(t1.IsAlive)
{
}
or
t1.Join();
or
myAutoResetEvent.WaitOne(); // myAutoResetEvent.Set() called in thread when it finished processing
I am not sure but, this might not be a good example but looking forward to one.
I know that they are all some form of signaling from the background thread to inform the calling/UI thread that the work has completed.
But using them end up blocking the UI until the thread completes. So I would like to know a real life scenario implementation of this.
I am thinking why not just run this process on the UI thread since you don't mind blocking it.
Edit: In otherwords, I am looking for the real uses of these blocking elements such as thread.Join() etc
A real life scenario relevant to your example would be where the reference to the thread is stored in a member of the window class, and it gets checked or waited for if some event triggers such as closing the window or the application exiting.
pseudo code:
class Window
{
private Thread _thread = null;
public void OnButtonClick()
{
_thread = CreateAndStartThread();
}
public void OnCloseWindow()
{
if(null != _thread)
_thread.Wait();
}
}
Related
So I'm still fairly new to C#. Im learning about threads.
So far I would like to know how to check if a thread has ended. I know that i can put a bool at the end of the method the thread uses and use that to determine if the thread ends.. but i dont want to do that, mainly because i want to learn the right way
so far I have this.
Thread testThreadd = new Thread(Testmethod);
testThreadd.Start();
testThreadd.Join();
I read about the thread.join(); class. To my understanding, that class only prevents any code after that from executing.. Please help
Well there are different ways that give different results
1 ) Wait until the work has finished. This is exactly what you've got with your code already. You'll start a thread and then wait for that thread to finish before continuing execution.
thread.Start();
thread.Join();
2) thread.ThreadState will tell you whether or not the thread has finished. In a basic scenario you could do the following. This would allow you to check the current thread state at any point in your code where you've got access to the state.
if(thread.ThreadState != ThreadState.Running){
// Thread has stopped
}
3) Using an event. A lot of Async examples will start some work and then trigger an event once the work has been completed. In this way you can sit watching for an event and respond once the work has completed. A usage example may look like the WebClient class
WebClient client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
Thread.Join() Blocks the thread you call it on until the thread you have called Join() on returns. Extending the example you have above:
Thread testThreadd = new Thread(Testmethod);
testThreadd.Start();
testThreadd.Join();
//Do more stuff here. This stuff will not start until testThreadd has completed its work.
you can do this
public partial class MainWindow : Window
{
Thread testThreadd;
public MainWindow()
{
InitializeComponent();
testThreadd = new Thread(Testmethod);
testThreadd.Start();
testThreadd.Join();
}
public void Testmethod()
{
// begining your treatement
// Ending your treatement
this.testThreadd.Abort();
}
}
Thread.Join method pauses current thread execution until second thread completes. It serves for thread synchronization and it's well enough indicator.
Otherwise, you should use Thread.IsAlive property to check if thread is running while not interrupting current thread. This property covers any state between Thread.Start and the end of the thread.
I am doing some heavy computations on the main thread and these computations cannot run on a separate thread.
I want to display a "Busy Indicator" (i.e., spinning widget) on the application UI when these computations are running. As such, I cannot show the busy indicator on main thread as the UI is locked while these computations are running.
To work around this issue, I tried to move the busy indicator to separate thread. With the help of this post I am able to place the busy indicator on separate thread. However, I am not able to communicate with this thread to start or stop the busy indicator.
private HostVisual CreateBusyIndicatorOnWorkerThread()
{
// Create the HostVisual that will "contain" the VisualTarget
// on the worker thread.
HostVisual hostVisual = new HostVisual();
Thread thread = new Thread(new ParameterizedThreadStart(BusyIndicatorWorkerThread));
thread.ApartmentState = ApartmentState.STA;
thread.IsBackground = true;
thread.Start(hostVisual);
// Wait for the worker thread to spin up and create the VisualTarget.
s_event.WaitOne();
return hostVisual;
}
private static AutoResetEvent s_event = new AutoResetEvent(false);
private void BusyIndicatorWorkerThread(object arg)
{
// Create the VisualTargetPresentationSource and then signal the
// calling thread, so that it can continue without waiting for us.
HostVisual hostVisual = (HostVisual)arg;
VisualTargetPresentationSource visualTargetPS = new VisualTargetPresentationSource(hostVisual);
s_event.Set();
// Create a MediaElement and use it as the root visual for the
// VisualTarget.
visualTargetPS.RootVisual = CreateBusyIndicator();
// Run a dispatcher for this worker thread. This is the central
// processing loop for WPF.
System.Windows.Threading.Dispatcher.Run();
}
private FrameworkElement CreateBusyIndicator()
{
var busyIndicator = new MyBusyIndicator();
//busyIndicator.DataContext = this.
Binding myBinding = new Binding("IsBusy");
myBinding.Source = this;
busyIndicator.SetBinding(MyBusyIndicator.IsBusyProperty, myBinding);
}
I always gets an exception "The calling thread cannot access this object because a different thread owns it". This is because I am trying to update the busy indicator from the main thread while the busy indicator is owned by a different thread.
I have also tried an approach given in this article,
private void CreateAndShowContent()
{
Dispatcher = Dispatcher.CurrentDispatcher;
VisualTargetPresentationSource source =
new VisualTargetPresentationSource(_hostVisual);
_sync.Set();
source.RootVisual = _createContent();
DesiredSize = source.DesiredSize;
_invalidateMeasure();
Dispatcher.Run();
source.Dispose();
}
But with this approach Dispatcher.Run() nothing happens until after the completion of the computations and then the busy indicator is displayed.
I want to communicate from main thread to the thread having busy indicator. Does anyone have an approach?
There is no reason to run "heavy computations" in UI thread. Even more - this is a bad practice. Instead use BackgroundWorker which will do work, meantime alive UI-thread will show Loading/Calculating:
var worker = new BackgroundWorker();
worker.DoWork += (s, e) => {
// This part will last at a separate thread without blocking UI.
// Excellent place for heavy computations.
}
worker.RunWorkerCompleted += (s, e) => {
// Here we're back to UI thread - so you can change states and stop animations.
}
// And finally start async computation
worker.RunWorkerAsync();
UI should contain BusyIndicator control which will be activated/stopped when you'll start/finish worker.
Please stop what you are doing... it is totally incorrect. #Anatolii Gabuza was correct... you shouldn't do any long running process using the UI thread as this will block it, making the application unusable at these times. Unless your long running process is rendering UI objects, then there really is no reason to do it using the UI thread... let us know what it is and we can help you to run it on a background thread correctly.
So you discovered that you can't display your busy indicator on the UI thread because it is busy with your long running process... at this point, most developers would realise their error, but unfortunately, not you. Instead of accepting that the long running process should be run on a background thread, you do the exact opposite and now want to display some UI element in a background thread, while blocking the UI thread with a long running process???
This is utter madness, if you want to avoid some horrendous problems, please stop. If you continue, then you'd better get used to seeing that exception:
The calling thread cannot access this object because a different thread owns it.
You need to invoke it busyContainer dispatcher. use as below
this.busyContainer.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
//update busy Container
}));
I got this from SO but cannot find it on SO
Run this on the UI thread and put in your task where very long task is
public class WaitCursor : IDisposable
{
private Cursor _previousCursor;
public WaitCursor()
{
_previousCursor = Mouse.OverrideCursor;
Mouse.OverrideCursor = Cursors.Wait;
}
#region IDisposable Members
public void Dispose()
{
Mouse.OverrideCursor = _previousCursor;
}
#endregion
}
using (new WaitCursor())
{
// very long task
}
I have this code that many threads can call to update the GUI:
MethodInvoker del = () => { lblInfo.Text = tmp; };
lblInfo.BeginInvoke(del);
(lblInfo is created by the GUI thread)
I also have this method called at button click executed by the GUI thread:
public void Stop()
{
isStopping = true;
crawler.Join();
foreach (Thread t in txtWorkers)
{
t.Join();
}
indexer.Join();
lblStatus.Text = "Stopped";
lblInfo.Text = "";
}
1 time over 100 run the program deadlock at Stop button click. I was not debugging when i saw the deadlock so i can't be sure about the state of the various threads but i'm almost sure that all the threads i'm joining will eventually reach the point where they check for
isStopping value and terminate. This leads me to think that there may be a problem with the BeginInvoke but can't really find it. It should be async so threads calling it (crawler & indexer) should not block. What happens if the GUI thread is executing Stop() and also must execute a call from BeginInvoke? Could this be the problem? Is there something i can't see about the thread i'm joining?
EDIT:
What the code looks like after the suggested changes:
public void Stop()
{
/*
...disable GUI
*/
isStopping = true; // Declared as volatile
lblStatus.Text = "Stopping...";
// Creating a thread that will wait for other threads to terminate
Task.Factory.StartNew(() =>
{
crawler.Join();
foreach (Thread t in txtWorkers)
{
t.Join();
}
indexer.Join();
// Adjust UI now that all threads are terminated
MethodInvoker del = () =>
{
/*
...enable GUI
*/
lblStatus.Text = "Not Running";
isStopping = false;
};
lblStatus.BeginInvoke(del);
});
}
It seems to be working, i hope that deadlock is gone...
I don't think it should be a problem, because you're using BeginInvoke rather than Invoke - the background threads will just proceed past that line without waiting for the GUI to catch up. If you're using Control.Invoke anywhere, that could cause a deadlock.
More importantly, using Join in your GUI thread is fundamentally a bad idea - the UI will be frozen until everything's finished. It would be better to disable any controls which could start anything new, set your isStopping flag, and then create a new thread to wait for all the threads to stop - and when all the threads have finished, then update the UI with BeginInvoke again. (If you're using .NET 4.5 you could also use an asynchronous method for this, creating and awaiting a task to wait for all the threads.)
Finally, if isStopping is just a bool field, there's no guarantee that your background threads will "see" the change from the UI thread. It's possible that making the field volatile would fix this, but the precise meaning of volatile scares me. An alternative would be to use the Interlocked class, or make it a property which obtains a lock for both reading and writing - that ensures appropriate memory barriers are in place.
I am trying to create a thread that contains a form progress bar (just a GIF image).
I have called StartProgress() right before a large method. Basically when the thread starts it loads up the ProgressBar form (which I want to show all the time, and just hide it when it's not needed) and with ProgressActive set to true, it should display the form until ProgressActive is false, then the form should be hidden (until progress is active again). Here is what I have so far, but it freezes up on me :(
public static string ProgressInfo="Test";
public static bool ProgressActive=true;
public static bool ThreadStarted = false;
public static void StartProgress()
{
while (!ThreadStarted)
{
Thread t = new Thread(new ThreadStart(Progress));
ThreadStarted = true;
t.Start();
}
}
public static void Progress()
{
while (ThreadStarted)
{
LoadingBar lb = new LoadingBar();
lb.Show();
lb.TopMost = true;
while (ThreadStarted)
{
if (ProgressActive)
{
lb.Visible = true;
lb.lblLoadingStatus.Text = ProgressInfo;
}
else
{
lb.Visible = false;
}
Thread.Sleep(1000);
}
}
}
EDIT: I am trying to do this within a static class.
Is there any reason for not using BackgroundWorker if using .NET 2.0 or higher?
The reason I am saying that is because BackgroundWorker is event based, so it exposes an event like ProgressChanged which can reduce the overall size of your code.
The freezing is due to the fact you are trying to change your progress bar contained on the UI thread from your worker thread. I would recommend raising an event from within your worker Progress function to a handler on the UI thread. You will need to marshall the call to the handler on the thread as below.
private object _lock = new object(); //should have class scope
private void ShowProgressControl(EventArgs e)
{
if (this.InvokeRequired)
{
lock (_lock)
{
EventHandler d = new EventHandler(ShowProgressControl);
this.Invoke(d, new object[] { e });
return;
}
}
else
{
//Show your progress bar.
}
}
Enjoy!
The problem is that you need a message loop for any UI element to work correctly. Since you are creating the form in a worker thread then there is no message loop running. To create the message loop you have to call Application.Run or Form.ShowDialog both of which are blocking calls. Obviously that solution would hang up your worker thread.
The best thing to do is to create a separate thread dedicated to running the message loop and which can safely handle forms and controls. Have the worker thread periodically publish progress information to a variable that can be shared between the worker thread and the UI thread. Then have the UI thread periodically poll (using System.Windows.Form.Timer) that shared variable and update the UI accordingly.
As a side note, I would avoid using Control.Invoke or Control.BeginInvoke to push the progress information to the UI thread. You situation seems to warrant the polling approach instead. The reasons for preferring polling over pushing are:
It breaks the tight coupling between the UI and worker threads that Control.Invoke imposes.
It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
The UI thread gets to dictate when and how often the update should take place.
There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).
You should create the progress bar on the main thread.
Make sure your heavy procedure runs from another thread.
Not sure if my title is worded well, but whatever :)
I have two threads: the main thread with the work that needs to be done, and a worker thread that contains a form with a progress bar and a cancel button. In normal code, it would be the other way around, but I can't do that in this case.
When the user clicks the cancel button, a prompt is displayed asking if he wants to really cancel the work. The problem is that work continues on the main thread. I can get the main thread to stop work and such, but I would like for it to stop doing work when he clicks "Yes" on the prompt.
Example:
// Main thread work starts here
t1 = new Thread(new ThreadStart(progressForm_Start));
t1.Start();
// Working
for (i = 0; i <= 10000; i++)
{
semaphore.WaitOne();
if (pBar.Running)
bgworker_ProgressChanged(i);
semaphore.Release();
if (pBar.IsCancelled) break;
}
t1.Abort();
// Main thread work ends here
// Start progress bar form in another thread
void progressForm_Start()
{
pBar.Status("Starting");
pBar.ShowDialog();
}
I could theoretically include a prompt in the cancelWatch() function, but then I would have to do that everywhere I'm implementing this class.
I have a couple of quick comments:
Avoid using Thread.Abort() here's why.
Make your thread a background thread: Thread.IsBackground = true (this will automatically exit the thread when your app exits).
Here is a detailed discussion on how to safely stop a thread from running: Is it safe to use a boolean flag to stop a thread from running in C#
To stop the work on the main thread you'd have to do something like this:
boolean volatile isRunning = true;
static void Main(...)
{
// ...
// Working
for (i = 0; i <= 10000; i++)
{
semaphore.WaitOne();
if (!isRunning) break; // exit if not running
if (pBar.Running)
bgworker_ProgressChanged(i);
semaphore.Release();
}
//...
t1.Interrupt();// make the worker thread catch the exception
}
//
void cancelButton_Click(object sender, EventArgs e)
{
isRunning = false; // optimistic stop
semaphore.Release();
}
I recommend using CancellationTokenSource, which can handle this kind of complex scenario. It's part of the Task Parallel Library but does not actually have to be used with Task objects; it can just as easily be used with old-style Thread objects.
Of course, if you have the time, I'd recommend defining the main thread's work as a Task object (running on the main UI thread by using TaskScheduler.FromCurrentSynchronizationContext).
Note that everything above assumes .NET 4.0. If you're still stuck on the old platform, you'll just have to have a bool cancelled; field protected by a lock or some such thing. Tip: don't call Thread.Abort; it's evil.