I'm doing an application that does some sort of scanning (it checks availability of URL's through a short list) and depending on the result, it adds to one or another listbox. if it exists, it goes to lstOK, else, it goes to lst404.
The issue is that these web checks take time (specially when it is OK), it takes an awfully long time, and inserts all the items in the listboxes in the end, while the form is "not responding" and nothing appears or can be clicked or displays any interaction.
Is there a way for the form to be still usable and the listboxes to update on the go ?
This should be simple, I just don't know it (yet)
I'm using C# in Visual Studio
--[update]--
The whole url checking is in one single function Start()
try the background worker
If this is a desktop application that is performing these "web checks" then you can use a BackgroundWorkerThread to perform the processing, and get the results.
Or you could do something like this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadWithDataReturnExample
{
public partial class Form1 : Form
{
private Thread thread1 = null;
public Form1()
{
InitializeComponent();
thread1 = new Thread(new ThreadStart(this.threadEntryPoint));
Thread1Completed += new AsyncCompletedEventHandler(thread1_Thread1Completed);
}
private void startButton_Click(object sender, EventArgs e)
{
thread1.Start();
//Alternatively, you could pass some object
//in such as Start(someObject);
//With apprioriate locking, or protocol where
//no other threads access the object until
//an event signals when the thread is complete,
//any other class with a reference to the object
//would be able to access that data.
//But instead, I'm going to use AsyncCompletedEventArgs
//in an event that signals completion
}
void thread1_Thread1Completed(object sender, AsyncCompletedEventArgs e)
{
if (this.InvokeRequired)
{//marshal the call if we are not on the GUI thread
BeginInvoke(new AsyncCompletedEventHandler(thread1_Thread1Completed),
new object[] { sender, e });
}
else
{
//display error if error occurred
//if no error occurred, process data
if (e.Error == null)
{//then success
MessageBox.Show("Worker thread completed successfully");
DataYouWantToReturn someData = e.UserState as DataYouWantToReturn;
MessageBox.Show("Your data my lord: " + someData.someProperty);
}
else//error
{
MessageBox.Show("The following error occurred:" + Environment.NewLine + e.Error.ToString());
}
}
}
#region I would actually move all of this into it's own class
private void threadEntryPoint()
{
//do a bunch of stuff
//when you are done:
//initialize object with data that you want to return
DataYouWantToReturn dataYouWantToReturn = new DataYouWantToReturn();
dataYouWantToReturn.someProperty = "more data";
//signal completion by firing an event
OnThread1Completed(new AsyncCompletedEventArgs(null, false, dataYouWantToReturn));
}
/// <summary>
/// Occurs when processing has finished or an error occurred.
/// </summary>
public event AsyncCompletedEventHandler Thread1Completed;
protected virtual void OnThread1Completed(AsyncCompletedEventArgs e)
{
//copy locally
AsyncCompletedEventHandler handler = Thread1Completed;
if (handler != null)
{
handler(this, e);
}
}
#endregion
}
}
If it's a web form look into AJAX.NET. There are several controls (UpdatePanel being one off the top of my head) that will help you do this.
Take a look at the toolkit.
EDIT: Only for web apps.
Application.DoEvents(); will do all the events that have happened up to that point.
so in your loop, after each website is checked, for example. do Application.DoEvents();
on the other hand if you just want to refresh your listboxes it'll be listboxname.Refresh();
both of these options, however will still have a time where it freezes while the website is pinged, unless you do many of them, which i dont suggets doing.
both methods also only use a single thread and is very linear.
The best option would be to create a new thread to do the tests on, or use a background worker that can do the tests on a seperate thread, so the events of the form can be handled instantly without a need to wait.
Manually controlling another thread shouldnt be too difficult.
here's an example.
using System.Threading;
public class MultiThreadingClass
{
private void FunctionForNewThread()
{
//do stuff
}
private void FunctionWithParameter(object param)
{
//Should do checks with typeof() on param before casting
int convertedparam = (int)param;
//do stuff
}
Thread t, t2;
static void Main()
{
ThreadStart ts = new ThreadStart(FunctionForNewThread);
t = new Thread(ts);
t.Start();
int x = 5;
ParameterizedThreadStart pts = new ParameterizedThreadStart(FunctionWithParameter);
t2 = new Thread(pts);
t2.Start(x);
}
}
it may be important to note here that you should never add a Thread as a local variable that will dissapear, as you can only really get the thread instance back by doing Thread.CurrentThread in the function which was called by the new thread, but if that thread has already locked up, you have a bit of a problem there :)
To easily handle Threads in a global variable either create an Array of threads and call Thread.Abort(); on each running thread when the program closes, or use the ThreadPool class in System.Threading.
Related
I am trying to get a thread to run in the following unfinished code. The basics of which are as follows; when the console app starts, it should start a thread which will go off, navigate to a web page (which will eventually do some processing) before stopping and killing off the separate thread. In conjunction, the main application will just provide a menu to the user until the app is exited. Eventually the navigation thread will be put into a separate method so that it is periodically called every so often but this should not be relevant to this question, I don't think...
My understanding is that the separate thread should just run alongside the main console application and terminate when it has completed its task just like a console would if you don't prevent it exiting?????
What it actually looks like is that it is not starting in the first place as I get no response by way of the browser_DocumentCompleted event triggering (I know the IP address is alive and active, as I've checked!!)
Can anyone shed any light on why the separate thread is not running, or appears not to be?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace ConsoleThreadTest
{
class Program
{
public delegate void Callback(string Status);
static void Main(string[] args)
{
NavigateToIPAddress GEIPA = new NavigateToIPAddress(new Uri("http://192.168.1.254"), new Callback(ResultCallback));
Thread PerformThreadTask = new Thread(new ThreadStart(GEIPA.PerformThreadTask));
PerformThreadTask.SetApartmentState(ApartmentState.STA);
PerformThreadTask.Start();
Console.WriteLine("{0}","Press escape key to exit");
while (true)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.Escape:
//Kill off thread if it is still running.
if (PerformThreadTask.ThreadState == ThreadState.Running)
{
PerformThreadTask.Abort();
}
Environment.Exit(0);
break;
default:
break;
}
}
}
}
public static void ResultCallback(string Status)
{
Console.WriteLine("{0}\t{1}", DateTime.Now.ToString("h:mm:ss"), Status);
}
public class NavigateToIPAddress
{
private Uri WebAddress;
private bool WebBrowserNavigationComplete = false;
// Delegate used to execute the callback method when the task is complete.
private Callback callback;
// The constructor obtains the state information and the callback delegate.
public NavigateToIPAddress(Uri IPAddressToNavigateTo, Callback callbackDelegate)
{
WebAddress = IPAddressToNavigateTo;
callback = callbackDelegate;
}
// The thread procedure performs the task and then invokes the callback delegate with the status.
public void PerformThreadTask()
{
var br = new WebBrowser();
br.DocumentCompleted += browser_DocumentCompleted;
try
{
br.Navigate(WebAddress);
}
catch (Exception e)
{
Console.WriteLine("{0}\tSome error occurred: {1}", DateTime.Now.ToString("h:mm:ss"), e.Message);
}
Application.Run();
while (WebBrowserNavigationComplete == false)
{
}
if (callback != null)
callback("Summit occurred");
}
private void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var br = sender as WebBrowser;
if (br.Url == e.Url)
{
Console.WriteLine("{0}\tNavigated to {1}", DateTime.Now.ToString("h:mm:ss"), e.Url);
WebBrowserNavigationComplete = true;
}
}
}
}
}
Here I have a catch 22 situation. On one hand, if I leave the code as is above, anything after the application.run() method does not get executed which means the WebBrowserNavigationComplete flag will never change and the callback will never be returned.
If however I move application.run() after
if (callback != null)
callback("Summit occurred");
the code will never reach this point in order to call application.run() as it is stuck in the while loop waiting for the WebBrowserNavigationComplete flag which will never change as the message loop is never started!!
I cannot believe I am the first to do anything like this? What is the normal way to overcome this deadlock?
Thanks
WebBrowser is a winforms construct, and requires an application loop be set up to process messages for it. Since you have a console application and no message loop, it won't function properly.
You'll need to explicitly create a new application loop using Application.Run (which needs to be run from an STA thread) for it to work.
I am currently writing my first program on C# and I am extremely new to the language (used to only work with C so far). I have done a lot of research, but all answers were too general and I simply couldn't get it t work.
So here my (very common) problem:
I have a WPF application which takes inputs from a few textboxes filled by the user and then uses that to do a lot of calculations with them. They should take around 2-3 minutes, so I would like to update a progress bar and a textblock telling me what the current status is.
Also I need to store the UI inputs from the user and give them to the thread, so I have a third class, which I use to create an object and would like to pass this object to the background thread.
Obviously I would run the calculations in another thread, so the UI doesn't freeze, but I don't know how to update the UI, since all the calculation methods are part of another class.
After a lot of reasearch I think the best method to go with would be using dispatchers and TPL and not a backgroundworker, but honestly I am not sure how they work and after around 20 hours of trial and error with other answers, I decided to ask a question myself.
Here a very simple structure of my program:
public partial class MainWindow : Window
{
public MainWindow()
{
Initialize Component();
}
private void startCalc(object sender, RoutedEventArgs e)
{
inputValues input = new inputValues();
calcClass calculations = new calcClass();
try
{
input.pota = Convert.ToDouble(aVar.Text);
input.potb = Convert.ToDouble(bVar.Text);
input.potc = Convert.ToDouble(cVar.Text);
input.potd = Convert.ToDouble(dVar.Text);
input.potf = Convert.ToDouble(fVar.Text);
input.potA = Convert.ToDouble(AVar.Text);
input.potB = Convert.ToDouble(BVar.Text);
input.initStart = Convert.ToDouble(initStart.Text);
input.initEnd = Convert.ToDouble(initEnd.Text);
input.inita = Convert.ToDouble(inita.Text);
input.initb = Convert.ToDouble(initb.Text);
input.initc = Convert.ToDouble(initb.Text);
}
catch
{
MessageBox.Show("Some input values are not of the expected Type.", "Wrong Input", MessageBoxButton.OK, MessageBoxImage.Error);
}
Thread calcthread = new Thread(new ParameterizedThreadStart(calculations.testMethod);
calcthread.Start(input);
}
public class inputValues
{
public double pota, potb, potc, potd, potf, potA, potB;
public double initStart, initEnd, inita, initb, initc;
}
public class calcClass
{
public void testmethod(inputValues input)
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
int i;
//the input object will be used somehow, but that doesn't matter for my problem
for (i = 0; i < 1000; i++)
{
Thread.Sleep(10);
}
}
}
I would be very grateful if someone had a simple explanation how to update the UI from inside the testmethod. Since I am new to C# and object oriented programming, too complicated answers I will very likely not understand, I'll do my best though.
Also if someone has a better idea in general (maybe using backgroundworker or anything else) I am open to see it.
First you need to use Dispatcher.Invoke to change the UI from another thread and to do that from another class, you can use events.
Then you can register to that event(s) in the main class and Dispatch the changes to the UI and in the calculation class you throw the event when you want to notify the UI:
class MainWindow : Window
{
private void startCalc()
{
//your code
CalcClass calc = new CalcClass();
calc.ProgressUpdate += (s, e) => {
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
};
Thread calcthread = new Thread(new ParameterizedThreadStart(calc.testMethod));
calcthread.Start(input);
}
}
class CalcClass
{
public event EventHandler ProgressUpdate;
public void testMethod(object input)
{
//part 1
if(ProgressUpdate != null)
ProgressUpdate(this, new YourEventArgs(status));
//part 2
}
}
UPDATE:
As it seems this is still an often visited question and answer I want to update this answer with how I would do it now (with .NET 4.5) - this is a little longer as I will show some different possibilities:
class MainWindow : Window
{
Task calcTask = null;
void buttonStartCalc_Clicked(object sender, EventArgs e) { StartCalc(); } // #1
async void buttonDoCalc_Clicked(object sender, EventArgs e) // #2
{
await CalcAsync(); // #2
}
void StartCalc()
{
var calc = PrepareCalc();
calcTask = Task.Run(() => calc.TestMethod(input)); // #3
}
Task CalcAsync()
{
var calc = PrepareCalc();
return Task.Run(() => calc.TestMethod(input)); // #4
}
CalcClass PrepareCalc()
{
//your code
var calc = new CalcClass();
calc.ProgressUpdate += (s, e) => Dispatcher.Invoke((Action)delegate()
{
// update UI
});
return calc;
}
}
class CalcClass
{
public event EventHandler<EventArgs<YourStatus>> ProgressUpdate; // #5
public TestMethod(InputValues input)
{
//part 1
ProgressUpdate.Raise(this, status); // #6 - status is of type YourStatus
// alternative version to the extension for C# 6+:
ProgressUpdate?.Invoke(this, new EventArgs<YourStatus>(status));
//part 2
}
}
static class EventExtensions
{
public static void Raise<T>(this EventHandler<EventArgs<T>> theEvent,
object sender, T args)
{
if (theEvent != null)
theEvent(sender, new EventArgs<T>(args));
}
}
#1) How to start the "synchronous" calculations and run them in the background
#2) How to start it "asynchronous" and "await it": Here the calculation is executed and completed before the method returns, but because of the async/await the UI is not blocked (BTW: such event handlers are the only valid usages of async void as the event handler must return void - use async Task in all other cases)
#3) Instead of a new Thread we now use a Task. To later be able to check its (successfull) completion we save it in the global calcTask member. In the background this also starts a new thread and runs the action there, but it is much easier to handle and has some other benefits.
#4) Here we also start the action, but this time we return the task, so the "async event handler" can "await it". We could also create async Task CalcAsync() and then await Task.Run(() => calc.TestMethod(input)).ConfigureAwait(false); (FYI: the ConfigureAwait(false) is to avoid deadlocks, you should read up on this if you use async/await as it would be to much to explain here) which would result in the same workflow, but as the Task.Run is the only "awaitable operation" and is the last one we can simply return the task and save one context switch, which saves some execution time.
#5) Here I now use a "strongly typed generic event" so we can pass and receive our "status object" easily
#6) Here I use the extension defined below, which (aside from ease of use) solve the possible race condition in the old example. There it could have happened that the event got null after the if-check, but before the call if the event handler was removed in another thread at just that moment. This can't happen here, as the extensions gets a "copy" of the event delegate and in the same situation the handler is still registered inside the Raise method.
I am going to throw you a curve ball here. If I have said it once I have said it a hundred times. Marshaling operations like Invoke or BeginInvoke are not always the best methods for updating the UI with worker thread progress.
In this case it usually works better to have the worker thread publish its progress information to a shared data structure that the UI thread then polls at regular intervals. This has several advantages.
It breaks the tight coupling between the UI and worker thread that Invoke imposes.
The UI thread gets to dictate when the UI controls get updated...the way it should be anyway when you really think about it.
There is no risk of overrunning the UI message queue as would be the case if BeginInvoke were used from the worker thread.
The worker thread does not have to wait for a response from the UI thread as would be the case with Invoke.
You get more throughput on both the UI and worker threads.
Invoke and BeginInvoke are expensive operations.
So in your calcClass create a data structure that will hold the progress information.
public class calcClass
{
private double percentComplete = 0;
public double PercentComplete
{
get
{
// Do a thread-safe read here.
return Interlocked.CompareExchange(ref percentComplete, 0, 0);
}
}
public testMethod(object input)
{
int count = 1000;
for (int i = 0; i < count; i++)
{
Thread.Sleep(10);
double newvalue = ((double)i + 1) / (double)count;
Interlocked.Exchange(ref percentComplete, newvalue);
}
}
}
Then in your MainWindow class use a DispatcherTimer to periodically poll the progress information. Configure the DispatcherTimer to raise the Tick event on whatever interval is most appropriate for your situation.
public partial class MainWindow : Window
{
public void YourDispatcherTimer_Tick(object sender, EventArgs args)
{
YourProgressBar.Value = calculation.PercentComplete;
}
}
You're right that you should use the Dispatcher to update controls on the UI thread, and also right that long-running processes should not run on the UI thread. Even if you run the long-running process asynchronously on the UI thread, it can still cause performance issues.
It should be noted that Dispatcher.CurrentDispatcher will return the dispatcher for the current thread, not necessarily the UI thread. I think you can use Application.Current.Dispatcher to get a reference to the UI thread's dispatcher if that's available to you, but if not you'll have to pass the UI dispatcher in to your background thread.
Typically I use the Task Parallel Library for threading operations instead of a BackgroundWorker. I just find it easier to use.
For example,
Task.Factory.StartNew(() =>
SomeObject.RunLongProcess(someDataObject));
where
void RunLongProcess(SomeViewModel someDataObject)
{
for (int i = 0; i <= 1000; i++)
{
Thread.Sleep(10);
// Update every 10 executions
if (i % 10 == 0)
{
// Send message to UI thread
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
(Action)(() => someDataObject.ProgressValue = (i / 1000)));
}
}
}
Everything that interacts with the UI must be called in the UI thread (unless it is a frozen object). To do that, you can use the dispatcher.
var disp = /* Get the UI dispatcher, each WPF object has a dispatcher which you can query*/
disp.BeginInvoke(DispatcherPriority.Normal,
(Action)(() => /*Do your UI Stuff here*/));
I use BeginInvoke here, usually a backgroundworker doesn't need to wait that the UI updates. If you want to wait, you can use Invoke. But you should be careful not to call BeginInvoke to fast to often, this can get really nasty.
By the way, The BackgroundWorker class helps with this kind of taks. It allows Reporting changes, like a percentage and dispatches this automatically from the Background thread into the ui thread. For the most thread <> update ui tasks the BackgroundWorker is a great tool.
If this is a long calculation then I would go background worker. It has progress support. It also has support for cancel.
http://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
Here I have a TextBox bound to contents.
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Write("backgroundWorker_RunWorkerCompleted");
if (e.Cancelled)
{
contents = "Cancelled get contents.";
NotifyPropertyChanged("Contents");
}
else if (e.Error != null)
{
contents = "An Error Occured in get contents";
NotifyPropertyChanged("Contents");
}
else
{
contents = (string)e.Result;
if (contentTabSelectd) NotifyPropertyChanged("Contents");
}
}
You are going to have to come back to your main thread (also called UI thread) in order to update the UI.
Any other thread trying to update your UI will just cause exceptions to be thrown all over the place.
So because you are in WPF, you can use the Dispatcher and more specifically a beginInvoke on this dispatcher. This will allow you to execute what needs done (typically Update the UI) in the UI thread.
You migh also want to "register" the UI in your business, by maintaining a reference to a control/form, so you can use its dispatcher.
Thank God, Microsoft got that figured out in WPF :)
Every Control, like a progress bar, button, form, etc. has a Dispatcher on it. You can give the Dispatcher an Action that needs to be performed, and it will automatically call it on the correct thread (an Action is like a function delegate).
You can find an example here.
Of course, you'll have to have the control accessible from other classes, e.g. by making it public and handing a reference to the Window to your other class, or maybe by passing a reference only to the progress bar.
Felt the need to add this better answer, as nothing except BackgroundWorker seemed to help me, and the answer dealing with that thus far was woefully incomplete. This is how you would update a XAML page called MainWindow that has an Image tag like this:
<Image Name="imgNtwkInd" Source="Images/network_on.jpg" Width="50" />
with a BackgroundWorker process to show if you are connected to the network or not:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
public partial class MainWindow : Window
{
private BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
// Set up background worker to allow progress reporting and cancellation
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
// This is your main work process that records progress
bw.DoWork += new DoWorkEventHandler(SomeClass.DoWork);
// This will update your page based on that progress
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
// This starts your background worker and "DoWork()"
bw.RunWorkerAsync();
// When this page closes, this will run and cancel your background worker
this.Closing += new CancelEventHandler(Page_Unload);
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BitmapImage bImg = new BitmapImage();
bool connected = false;
string response = e.ProgressPercentage.ToString(); // will either be 1 or 0 for true/false -- this is the result recorded in DoWork()
if (response == "1")
connected = true;
// Do something with the result we got
if (!connected)
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_off.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
else
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_on.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
}
private void Page_Unload(object sender, CancelEventArgs e)
{
bw.CancelAsync(); // stops the background worker when unloading the page
}
}
public class SomeClass
{
public static bool connected = false;
public void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
int i = 0;
do
{
connected = CheckConn(); // do some task and get the result
if (bw.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
Thread.Sleep(1000);
// Record your result here
if (connected)
bw.ReportProgress(1);
else
bw.ReportProgress(0);
}
}
while (i == 0);
}
private static bool CheckConn()
{
bool conn = false;
Ping png = new Ping();
string host = "SomeComputerNameHere";
try
{
PingReply pngReply = png.Send(host);
if (pngReply.Status == IPStatus.Success)
conn = true;
}
catch (PingException ex)
{
// write exception to log
}
return conn;
}
}
For more information: https://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
I'm in trouble with this code. I'm using .Net (C#) with Winform Application.
I need to run RunProgram Method which has loop that make a call to a method named ListLoop.
In this function there is a forach that creates 1 thread for each element a list.
(Please Read the code before continue to read the description so you could understand what i'm talking about )
The problem is that if i dont make any control in the "for" (RunProgram Method) it starts (of course) 10 times The ListLoop Function.
So i would add in that "For" a code which wait that all Threads are terminated, so i can do Something and Then continue with the next loop.
I tried thread.join() but it freeze my UI application
(it's Application which inside has a WebControl Browser).
Even if i Try to play with returnThred and with thread.isAlive it still freezes UI.
If i hadn't the Multithread i'll dont stay here with those problems but it's the only good solution for my program i think.
Is there a simple solution for my code?
Update: Maybe it'snt clear my question.
I just want run the ListLoop X times but before start the next one i want wait that all threads are dead (That ones of the first call) so i can do some control and continue with the loop inside RunProgram.
Update2 I have this UI application which has a WebBrowser Control. I have a List of Links Object (each element of this class has string url and idHost =1 2 3 4...1 for google 2 for yahoo etc...)
I want make a loop where my program start a newTab (with Method AddTab(url) ) for each element of the list. When all links are opened (and so all the threads are deads and) i need to do something that count how many pages opened and who was the idHost save it and start another Loop with the list(This list take random element from a Bigger List)
Update 3 I just tried with BackGround Worker but i cant use it cause the WebKit that i'm using give COM error. Something for the Tasks.
Thanks
private void RunProgram()
{
List<Links> TheList = new List<Links>();
//Do something to Populate the List
List<System.Threading.Thread> returnThread = new List<.....>();
for(int i=0; i<10; i++)
{
returnThread=ListLoop(TheList);
// ???????????
// When Loop Method has finished and all threads stopped
// Do something
// Continue for the next Loop
}
}
private List<System.Threading.Thread> ListLoop(List<Links> list)
{
List<System.Threading.Thread> threading = new List<System.Threading.Thread>();
foreach (Links link in list)
{
Links tmp = new Links();
tmp = link;
var thread = new System.Threading.Thread(p =>
{
lock (l)
{
Action action = () =>
{
AddTab(tmp);
};
this.Invoke(action);
if (tmp.idHost == 1) //if IDhost == Google wait 5sec
{
System.Threading.Thread.Sleep(5000);
}
else
{
System.Threading.Thread.Sleep(2000);
}
}
});
threading.Add(thread);
thread.Start();
}
return threading;
}
If RunProgram is called from your main application, it will freeze your main form if it sleeps or waits for threads to terminate. You should run the RunProgram method in its own thread, so it can then create the worker threads, and then you can wait for the threads to complete in your for loop before starting new ones.
You could use AutoResetEvent to signal when threads are finished so you can simply wait on the AutoResetEvent before continuing the loop. The BackgroundWorker class may be a good class to look at for creating your threads as well.
I'm not sure if I understood your question properly, but:
You work asynchronously here... You can't wait in your code without stopping the GUI.
I think your solution will be to separate your function into 2 parts - The 1st one you just written, and the second one works after the threads are all dead.
For the second part (check the threads) I'd use either another thread (That waits until the threads are dead than continues to your code) or a Timer if you'd like to save threads and integrate easily into the main form
UPDATE:
Here is an example of how a blocking function that doesn't block the GUI thread:
using System.Windows.Forms;
using System.Threading;
using System;
namespace Threads
{
public partial class Form1 : Form
{
public event EventHandler OnSomethingFinishes;
public Form1()
{
InitializeComponent();
OnSomethingFinishes += new EventHandler(Form1_OnSomethingFinishes);
}
void Form1_OnSomethingFinishes(object sender, EventArgs e)
{
this.Invoke(new EventHandler(Form1_OnSomethingFinishesSafe), sender, e);
}
void Form1_OnSomethingFinishesSafe(object sender, EventArgs e)
{
this.Text = "Done!";
}
private void BlockingFunction(object a_oParameter)
{
// Do something that blocks
Thread.Sleep(2000);
if (OnSomethingFinishes != null)
OnSomethingFinishes(this, null);
}
private void button1_Click(object sender, EventArgs e)
{
Thread l_oThread = new Thread(BlockingFunction);
l_oThread.Start();
this.Text = "Please Wait...";
}
}
}
button1 starts the process. Notice that you have to invoke the function after the event is handled to move the control to the main GUI thread
Hope this helps
I've been tasked with working on a download queuing system but I'm a bit confused about where to start.
Essentially what we need to do is to have something like a download manager (but not as fully blown). We have about 20-100 files to download, we give the user a UI (with a listview) to allow them to pause, stop, or move the priorty of jobs around.
What I'm confused about is the data-structure to use, a Priority Queue seems like the way to go from my research, but I'm confused about how to make it work. Do I have a background thread that peeks into the Queue and picks up the next task and carries it forward? I need to provide progress too as the files are being downloaded - they are quite large, sometimes 120Mb (but its local, so no more than 10mins).
Sometimes they need to pause a job and shove a job higher up in the queue as its deemed urgent.
Its not a download manager, so no throttling etc issues. How do people write things like this?
I was thinking of having an interface like IDownloadTask which describes the task to carry out, have a few properties and an event to expose its Progress (which gets wired up when the tasks runs).
Then put that IDownloadTask into the queue with a priority. A background worker picks it up (the PriorityQUeue will need to be synchronised I guess) and then executes the .Execute() method in the interface implementation on a seperate thread.
Does this sound reasonable? Are there any concrete examples anyone can show me somewhere?
EDIT
Wow thanks for the reply and the vote of confidence, I should mention that I'm using .NET 2.0 (we can't move higher because of Windows compatibility requirements for Windows 9x).
As for tracking progress, your thread can report progress using events, as well as completion. Here is an example with a completion event, but the same concept would work for a Status update event. You'd just change the class that holds the data so that it can pass info about progress.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadWithDataReturnExample
{
public partial class Form1 : Form
{
private Thread thread1 = null;
public Form1()
{
InitializeComponent();
thread1 = new Thread(new ThreadStart(this.threadEntryPoint));
Thread1Completed += new AsyncCompletedEventHandler(thread1_Thread1Completed);
}
private void startButton_Click(object sender, EventArgs e)
{
thread1.Start();
//Alternatively, you could pass some object
//in such as Start(someObject);
//With apprioriate locking, or protocol where
//no other threads access the object until
//an event signals when the thread is complete,
//any other class with a reference to the object
//would be able to access that data.
//But instead, I'm going to use AsyncCompletedEventArgs
//in an event that signals completion
}
void thread1_Thread1Completed(object sender, AsyncCompletedEventArgs e)
{
if (this.InvokeRequired)
{//marshal the call if we are not on the GUI thread
BeginInvoke(new AsyncCompletedEventHandler(thread1_Thread1Completed),
new object[] { sender, e });
}
else
{
//display error if error occurred
//if no error occurred, process data
if (e.Error == null)
{//then success
MessageBox.Show("Worker thread completed successfully");
DataYouWantToReturn someData = e.UserState as DataYouWantToReturn;
MessageBox.Show("Your data my lord: " + someData.someProperty);
}
else//error
{
MessageBox.Show("The following error occurred:" + Environment.NewLine + e.Error.ToString());
}
}
}
#region I would actually move all of this into it's own class
private void threadEntryPoint()
{
//do a bunch of stuff
//when you are done:
//initialize object with data that you want to return
DataYouWantToReturn dataYouWantToReturn = new DataYouWantToReturn();
dataYouWantToReturn.someProperty = "more data";
//signal completion by firing an event
OnThread1Completed(new AsyncCompletedEventArgs(null, false, dataYouWantToReturn));
}
/// <summary>
/// Occurs when processing has finished or an error occurred.
/// </summary>
public event AsyncCompletedEventHandler Thread1Completed;
protected virtual void OnThread1Completed(AsyncCompletedEventArgs e)
{
//copy locally
AsyncCompletedEventHandler handler = Thread1Completed;
if (handler != null)
{
handler(this, e);
}
}
#endregion
}
}
Here are two C# projects that you can probably use to get you started.
MyDownloader: A Multi-thread C#
Segmented Download Manager
Multi-threaded file download
manager
Here are is a mini implementation you can start out with:
C# Threading issue with AutoResetEvent
You will probably want to have more that 1 processing thread, and you will probably need to add some comms back to the piece of data being processed so you can pause etc ...
I have a third party library containing a class which performs a function asynchronously. The class inherits from the Form. The function basically performs a calculation based on data stored in a database. Once it has finished, it calls a _Complete event in the calling form.
What I would like to do is call the function synchronously but from a non-windows form application. The problem is, no matter what I do, my application blocks and the _Complete event handler never fires. From a windows form I can simulate the function running synchronously by using a "complete" flag and a "while (!complete) application.doevents", but obviously application.doevents isnt available in a non-windows form application.
Is there something that would stop me using the class's method outside of a windows form application (due to it inheriting from 'Form') ?
Is there some way I can work around this ?
Thanks,
Mike
At a stab it might be worth trying something like the following which uses a WaitHandle to block the current thread rather than spinning and checking a flag.
using System;
using System.Threading;
class Program
{
AutoResetEvent _autoEvent;
static void Main()
{
Program p = new Program();
p.RunWidget();
}
public Program()
{
_autoEvent = new AutoResetEvent(false);
}
public void RunWidget()
{
ThirdParty widget = new ThirdParty();
widget.Completed += new EventHandler(this.Widget_Completed);
widget.DoWork();
// Waits for signal that work is done
_autoEvent.WaitOne();
}
// Assumes that some kind of args are passed by the event
public void Widget_Completed(object sender, EventArgs e)
{
_autoEvent.Set();
}
}
I've got some more information on this problem (I'm working in the same team as mikecamimo).
The problem also occurs in the Windows Forms application, when replicated correctly. In the original OP, the problem didn't occur in the windows form because there was no blocking. When blocking is introduced by using a ResetEvent, the same problem occurs.
This is because the event handler (Widget_Completed) is on the same thread as the method calling Widget.DoWork. The result that AutoResetEvent.WaitOne(); blocks forever because the event handler is never called to Set the event.
In a windows forms environment this can worked around by using Application.DoEvents to poll the message queue and allow the event the be handled. See below.
using System;
using System.Threading;
using System.Windows.Forms;
class Program
{
EventArgs data;
static void Main()
{
Program p = new Program();
p.RunWidget();
}
public Program()
{
_autoEvent = new AutoResetEvent(false);
}
public void RunWidget()
{
ThirdParty widget = new ThirdParty();
widget.Completed += new EventHandler(this.Widget_Completed);
data = null;
widget.DoWork();
while (data == null);
Application.DoEvents();
// do stuff with the results of DoWork that are contained in EventArgs.
}
// Assumes that some kind of args are passed by the event
public void Widget_Completed(object sender, EventArgs e)
{
data = e;
}
}
In a non windows forms application, such as a Windows Service, Application is not available so DoEvents cannot be called.
The problem is one of threading and that widget.DoWork's associated event handler somehow needs to be on another thread. This should prevent AutoResetEvent.WaitOne from blocking indefinitely. I think... :)
Any ideas on how to accomplish this would be fantastic.
AutoResetEvent _autoEvent = new AutoResetEvent(false);
public WebBrowser SyncronNavigation(string url)
{
WebBrowser wb = null;
wb = new WebBrowser();
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
wb.ScriptErrorsSuppressed = true;
wb.Navigate(new Uri(url));
while (!_autoEvent.WaitOne(100))
Application.DoEvents();
return wb;
}
void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//throw new NotImplementedException();
_autoEvent.Set();
}
Do you have the source for the component? It sounds like it's relying on the fact it will be called from a WinForms environment (must be a good reason why a library inherits from Form!), but it's hard to know for sure.