How to raise cross thread event - c#

How can I raise the the event GeocodeAddressEventHandler from another thread?
System.Threading.Thread MapThread;
WinformMap map ;
public delegate void GeocodeAddressEventHandler(object sender, EventArgs e);
public event GeocodeAddressEventHandler GeocodeAddressEvent;
//How to Raise this Event from another thread??
public void GeocodeAddress_Raised(object sender, EventArgs e)
{
MapLib.GeocodeAddress("12798 1ST ST", "", "", "");
}
public bool LoadMap(string restorepoint)
{
////////////////////////Engine Controls////////////////////////////////////////////////////////
try
{
System.ServiceModel.OperationContext context = System.ServiceModel.OperationContext.Current;
//This is to instantiate a winform from a Console (will convert to service shortly)
MapThread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate
{
using (System.ServiceModel.OperationContextScope scope = new System.ServiceModel.OperationContextScope(context))
{
this.GeocodeAddressEvent += new GeocodeAddressEventHandler(GeocodeAddress_Raised);
}
}));
MapThread.SetApartmentState(System.Threading.ApartmentState.STA);
MapThread.Start();
MapThread.Join();
}
catch (Exception ex)
{
return false;
}
return true;
}
Actually it turned out that the thread was terminating after the scope of the delegate terminated. This might be a dumb way to do it, but I put a while Queue.empty { sleep } in that scope so it never terminated, then I launched the LoadMap from yet another thread, so that it jam up my WCF service waiting for the neverending queue to terminate.

Take a look at
http://www.codeproject.com/KB/cs/Cross_thread_Events.aspx
See also BackgroundWorker class : http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Take a look at the Invoke() method:
http://msdn.microsoft.com/library/zyzhdc6b.aspx

Related

Unable to modify variables from separate thread

So I'm making a C# app which has to continuously read and display the contents of a text file, while allowing the user to enter something into a text box and append it to the end of that very file.
I'm doing this by running my read method on a separate thread, however changing the variable which stores the display text-files contents is what's causing a problem. Initially I tried having a method which did this, however that's not working and gave a 'cross-thread-operation-not-valid' error. I then tried applying some code I found on MSDN, but now after updating the variable once the thread ended!
Please help.
partial class MainForm
{
delegate void SetTextCallback(string text);
public static string msg;
public static string name;
public void InitClient()
{
name = "public.txt";
Console.WriteLine(name);
if(!File.Exists(name))
{
File.Create(name);
File.AppendAllText(name, "Welcome to " + name);
}
Thread Read = new Thread(new ThreadStart(this.Client));
Read.Start();
while(!Read.IsAlive);
}
public void WriteText()
{
File.AppendAllText(name, this.InputBox.Text);
this.InputBox.Clear();
}
private void SetText(string text)
{
if (this.OutPut.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.OutPut.Text = text;
}
}
public void Client()
{
msg = File.ReadAllText(name);
Console.WriteLine(msg);
Thread.Sleep(300);
this.SetText(msg);
}
}
Why is the thread behaving like this. How can I modify my code so that the contents of the output box always equals that of the text file.
Any suggestions welcome.
You've got multiple problems here,
the use of the File is probably not thread-safe.
your method does not repeat
your are Sleep()ing on a Thread
You can solve all of them by ditching the Thread and use a simple Timer.
Try using a background worker instead of creating a new thread. The background worker will run its content in a seperate thread, and allows you to report 'progress' while its working. This progress report will always be run on the UI-thread (or the thread which started the background worker).
It also has an event which is called when the background worker is finished. This is also run on the UI thread.
This example should get you started.
Update: Added some very basic error handling as suggested
The idea is to use the UserData (2nd argument) of ReportProgress to do updates on the UI thread whenever you need to. In this case it is a string, but this can be any object.
Furthermore, you can use the Result of the DoWorkEventArgs to produce a final result from the background work. In this case, I return any exception which was thrown, or null otherwise, but you can return whatever you want here as well.
It is, as Henk mentioned in his comment, very important to handle errors that occur inside the DoWork callback, because exceptions etc which occurs here will be swallowed and the worker will complete as if nothing bad happened.
private BackgroundWorker _backgroundWorker;
public Form1()
{
InitializeComponent();
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.WorkerSupportsCancellation = true;
// This is the background thread
_backgroundWorker.DoWork += BackgroundWorkerOnDoWork;
// Called when you report progress
_backgroundWorker.ProgressChanged += BackgroundWorkerOnProgressChanged;
// Called when the worker is done
_backgroundWorker.RunWorkerCompleted += BackgroundWorkerOnRunWorkerCompleted;
}
private void BackgroundWorkerOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
{
if (runWorkerCompletedEventArgs.Result != null)
{
// Handle error or throw it
throw runWorkerCompletedEventArgs.Result as Exception;
}
textBox1.Text = "Worker completed";
}
private void BackgroundWorkerOnProgressChanged(object sender, ProgressChangedEventArgs progressChangedEventArgs)
{
textBox1.Text = progressChangedEventArgs.UserState as string;
}
private void BackgroundWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
try
{
for (int i = 0; i < 100 && !_backgroundWorker.CancellationPending; i++)
{
_backgroundWorker.ReportProgress(0, i + " cycles");
Thread.Sleep(100);
}
}
catch (Exception ex)
{
doWorkEventArgs.Result = ex;
}
}
private void startButton_Click(object sender, EventArgs e)
{
if (!_backgroundWorker.IsBusy)
_backgroundWorker.RunWorkerAsync();
}
private void cancelButton_Click(object sender, EventArgs e)
{
if(_backgroundWorker.IsBusy)
_backgroundWorker.CancelAsync();
}

C# How to stop running backgroundWorker without cancellationPending

is there any way to stop backgroundWorker thread without cancellationPending?
I have code like this:
DoWorkFunction
{
if(worker.cancellationPending == true) return; //this works great but
VeryLongTimeComputingFunc();//this function take a lot of time and if it starts i can't stop it with cancellationPending
...Do something
}
Is there any way to stop worker even if it started VeryLongTimeComputingFunc()?
Maybe you could fire an "CancelWorker" event in your "VeryLongTimeComputingFunc" and in the EventHandler you stop the BackgroundWorker with "worker.CancelAsync()".
This should work:
class BackgroundClass
{
public event EventHandler CancelWorker;
BackgroundWorker worker = new BackgroundWorker();
BackgroundClass()
{
CancelWorker += new EventHandler(BackgroundClass_CancelWorker);
}
void BackgroundClass_CancelWorker(object sender, EventArgs e)
{
worker.CancelAsync();
}
void RunBackgroundWorker()
{
worker.DoWork += (sender, args) =>
{
VeryLongTimeComputingFunction();
};
}
void VeryLongTimeComputingFunction()
{
if (CancelWorker != null)
{
CancelWorker(this, new EventArgs());
}
}
}
This would require that you can change something in the "VeryLongTimeComputingFunction()"
Assuming you can not add proper cancellation support inside VeryLongTimeComputingFunction, your best option is to save a reference to the BGW's thread and call Abort on it.
Keep in mind this is not generally recommended as it may involve a messy cleanup.
To be safe, you should catch any ThreadAbortedException raised in your long function.
private Thread bgThread;
void DoWorkFunction()
{
bgThread = Thread.CurrentThread;
try
{
VeryLongTimeComputingFunc();
}
catch (ThreadAbortedException e)
{
//do any necessary cleanup work.
bgThread = null;
}
}
void CancelBGW()
{
if (bgThread != null)
{
bgThread.Abort();
}
}
Depending on when and how CancelBGW is called, you may also need a lock around assignments of bgThread.

How to make sure that a thread is awaiting for events?

I wonder how to make sure that a thread is awaiting for events.
Let say I've a component that raises events:
public delegate void TestHandler(object sender, EventArgs eventArgs);
class Producer
{
public event TestHandler Handler;
public void InvokeHandler(EventArgs eventargs)
{
var handler = Handler;
if (handler != null) handler(this, eventargs);
}
public Producer()
{
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep( (new Random()).Next(0,100) );
InvokeHandler(new EventArgs());
} }); } }
And a Listener:
class Listener
{
private readonly BlockingCollection<EventArgs> _blockingCollection;
public Listener()
{
var producer = new Producer();
_blockingCollection = new BlockingCollection<EventArgs>(10);
producer.Handler += producer_Handler;
}
void producer_Handler(object sender, EventArgs eventArgs)
{
_blockingCollection.TryAdd(eventArgs); //no error handling for simplicity sake
}
internal void ProcessEvents()
{
while (true)
{
EventArgs eventArgs;
try
{
if (_blockingCollection.TryTake(out eventArgs))
Console.WriteLine("Received event");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
} } } }
If I would start it as:
class Program
{
static void Main(string[] args)
{
var listner = new Listener();
listner.ProcessEvents();
} }
I got expected behaviour (from time to time I'm getting the event through blocking collection.
However if I would wrap this call in Task:
Task.Factory.StartNew(() => {
var listner = new Listener();
listner.ProcessEvents(); });
I will never got into the processing part.
Any idea why it would be? Do I miss something obvious?
On the side, does someone know a good description of a pattern that will help here?
I'm looking to pick-up events on one thread (preferably not the main application thread), then process them on a separate thread at the same time blocking if the number of events is getting too high (typical thresholdingI assume)
Thanks in advance,
Stupid me...
When I wrap my call in Task it is run on a Background thread.
I should have wait for the task to finish before quiting.
Having done that, that is assigning:
var task = Task.Factory.StartNew(/*task body*/);
task.Wait();
and waiting I have got what I want.
In order to figure out what's going on you should put some logging messages and verify that no exceptions are thrown when when you start the new task:
Thread listenerThread = new Thread(() =>
{
// print a message when the task is started
Console.WriteLine("Task started!");
var listner = new Listener();
listner.ProcessEvents();
});
// set your thread to background so it doesn't live on
// even after you're
listenerThread.IsBackground = true;
listenerThread.Start();
Thread.Join() does the same thing as Task.Wait(). You can call it without specifying a timeout, you can specify an infinite timeout or if you want your test to stop waiting for the thread to finish, then you specify a timeout in milliseconds:
// this will block until the thread is complete
listenerThread.Join(Timeout.Infinite);
If you need to stop the test, then you have to perform an asynchronous interrupt. Interrupt raises a ThreadInterruptedException inside the Thread which you're supposed to catch (as shown in the ProcessEvents method):
listenerThread.Interrupt();
Additionally, you're using a blocking collection, but you're not utilizing the blocking functionality of the collection. There is no reason why you should keep retrying when there is nothing in the collection, instead you would rather block until there is something in it (which is what this collection is designed to do):
internal void ProcessEvents()
{
while (true)
{
try
{
var myEvent = _blockingCollection.Take();
Console.WriteLine("Received event");
}
catch(ThreadInterruptedException)
{
Console.WriteLine("Thread interrupted!");
break;// break out of the loop!
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
// Do you REALLY want to keep going if there is an unexpected exception?
// Consider breaking out of the loop...
}
}
}

Why does setting a form's enabled property crash the application?

private void launchbutton_Click(object sender, EventArgs e)
{
launchbutton.Enabled = false;
Process proc = new Process();
proc.EnableRaisingEvents = true;
proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
//The arguments/filename is set here, just removed for privacy.
proc.Exited += new EventHandler(procExit);
proc.Start();
}
private void procExit(object sender, EventArgs e)
{
MessageBox.Show("YAY","WOOT");
Thread.Sleep(2000);
launchbutton.Enabled = true;
}
2 Seconds after I quit the created process, my program crashes. Why?
You're modifying a winform control on a different thread than the one that created that control (the main UI thread). Winform controls are not thread-safe and typically will throw an exception if you modify their state from any thread other than the one that created it.
You can accomplish this using the InvokeRequired property and BeginInvoke method found on the Form or control object.
For example, something like this:
private void procExit(object sender, EventArgs e)
{
MessageBox.Show("YAY", "WOOT");
Thread.Sleep(2000);
// ProcessStatus is just a class I made up to demonstrate passing data back to the UI
processComplete(new ProcessStatus { Success = true });
}
private void processComplete(ProcessStatus status)
{
if (this.InvokeRequired)
{
// We are in the wrong thread! We need to use BeginInvoke in order to execute on the correct thread.
// create a delegate pointing back to this same function, passing in the same data
this.BeginInvoke(new Action<ProcessStatus>(this.processComplete), status);
}
else
{
// check status info
if (status.Success)
{
// handle success, if applicable
}
else
{
// handle failure, if applicable
}
// this line of code is now safe to execute, because the BeginInvoke method ensured that the correct thread was used to execute this code.
launchbutton.Enabled = true;
}
}

C# Threading and using AutoResetEvent

I have the following code in a class library. And I wait for a call back into my main application. I am making a DownloadStringAsync call so I have to wait a few seconds to get the callback after it has finished. I have a 3 of these calls to wait for, so in my main application I am using AutoResetEvent to wait all of them to finish. So I will block until they have been set in the callback function.
However, after testing the callback don't get called. I am thinking when the code gets blocked by the AutoResetEvent its blocking the DownloadStringAsync. As when I comment out this code everything works fine.
So I think as soon as I make a call to: objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber);
And when the code reaches here: handle.WaitOne();
It will block the code in the class library.
Many thanks for any advice.
In my class library code sample.
// Event handler that makes a call back in my main application
// Event handler and method that handles the event
public EventHandler<NoGatewayEventArgs> NoGatewayCompletedEvent;
// The method that raises the event.
private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
if (NoGatewayCompletedEvent != null)
{
NoGatewayCompletedEvent(this, e);
}
}
// Start the Async call to find if NoGateway is true or false
public void NoGatewayStatus(string sipUsername, string phoneNumber)
{
string strURL = string.Format("http://xxxxxxxxxxxxxxx={0}&CalledNumber={1}", sipUsername, phoneNumber);
if (!wc.IsBusy)
{
try
{
string errorMsg = string.Empty;
wc.DownloadStringAsync(new Uri(strURL));
}
catch (WebException ex)
{
Console.WriteLine("IsNoGateway: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("IsNoGateway: " + ex.Message);
}
}
else
{
Console.WriteLine("WebClient: IsNoGateWay(): Busy please try again");
}
}
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
if (e.Result == "No gateway")
{
OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.VALIDATION_FAILED));
Console.WriteLine("NoGatway() DownloadedCompleted: " + e.Result);
}
else
{
OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.OK));
Console.WriteLine("NoGateway() DownloadCompleted: " + e.Result);
}
}
else
{
this.OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.SERVER_FAILED));
Console.WriteLine("No Gateway: DownloadCompleted() Error: " + e.Error.Message);
}
}
In my main application I register this callback. And wait for the for the result. Then set the AutoResetEvent.
ManualResetEvent[] waitValidateCallResponse = new ManualResetEvent[]
{ new ManualResetEvent(false), new ManualResetEvent(false), new ManualResetEvent(false) };
// Event handler for NoGateway event
private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
Console.WriteLine("OnNoGatewayComleted: " + e.noGateway);
waitValidateCallResponse[0].Set();
}
The part when I am calling and blocking.
NoGateway objNoGateway = new NoGateway()
objNoGateway.NoGatewayCompletedEvent += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);
objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber);
// Block here - Wait for all reponses to finish before moving on
waitEvent.WaitOne(5000, true);
Console.WriteLine("All thread finished");
======================== Edit and added the other 2 callbacks as not to confuse the issue of me just having only one ======================
private void OnCalledNumberBlockedCompleted(object sender, CalledNumberBlockedEventArgs e)
{
Console.WriteLine("OnCalledNumberBlockedCompleted: " + e.CalledNumberBlocked);
waitValidateCallResponse[1].Set();
}
private void OnValidTelephoneNumberCompleted(object sender, ValidTelephoneNumberEventArgs e)
{
Console.WriteLine("OnValidTelephoneNumberCompleted: " + e.validTelephoneNumber);
waitValidateCallResponse[2].Set();
}
Is it as simple as: you always call Set on index 0?
private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
Console.WriteLine("OnNoGatewayComleted: " + e.noGateway);
waitValidateCallResponse[0].Set();
}
Try something along these lines:
public void NoGatewayStatus (string sipUsername, string phoneNumber) {
string strURL = string.Format( "http://xxxxxxxxxxxxxxx={0}&CalledNumber={1}", sipUsername, phoneNumber );
ManualResetEvent wait1 = new ManualResetEvent( false );
WebClient wc = new WebClient();
Thread thr = new Thread( DownloadSomeStuff );
thr.Start( new DlArguments( strURL, wait1 ) );
// do the other three
if ( !wait1.WaitOne( 10000 ) ) {
Console.WriteLine( "DownloadSomeStuff timed out" );
return;
}
if ( !wait2.WaitOne( 10000 ) ) {
Console.WriteLine( "DownloadOtherStuff timed out" );
return;
}
if ( !wait3.WaitOne( 10000 ) ) {
Console.WriteLine( "DownloadMoreStuff timed out" );
return;
}
}
public void DownloadSomeStuff (object p_args) {
DlArguments args = (DlArguments) p_args;
try {
WebClient wc = new WebClient();
wc.DownloadString( args.Url );
args.WaitHandle.Set();
} catch ( Exception ) {
// boring stuff
}
}
private class DlArguments
{
public DlArguments (string url, ManualResetEvent wait_handle) {
this.Url = url;
this.WaitHandle = wait_handle;
}
public string Url { get; set; }
public ManualResetEvent WaitHandle { get; set; }
}
Does this do it?
After lots of edits, I think I might understand the problem. Windows Forms applications have one main thread; this thread is used to process messages. So when your main thread is blocking, your application can't receive events. And you use WaitOne to keep the main thread blocked.
I'd move the WaitOne() checks to a separate timer thread.
Or you could wait for a limited time, and instruct the application to process messages in between:
foreach (WaitHandle handle in waitValidateCallResponse)
{
while (!handle.WaitOne(300))
Application.ProcessMessages();
Console.WriteLine("events.WaitOne(): " + handle.ToString());
}
The later approach is not something you should do in a library though. It's something of an anti-pattern I think.
The snippet code is peculiar
// Event handler that makes a call back in my main application
// Event handler and method that handles the event
public EventHandler<NoGatewayEventArgs> NoGatewayCompletedEvent;
// The method that raises the event.
public void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
if (NoGatewayCompletedEvent != null)
{
NoGatewayCompletedEvent(this, e);
}
}
However in the 2nd last snippet, you attach an event handler for this event as follows.. OnNoGatewayCompleted seems to be a helper method to raise the event.. (it should not be public) but here it seems you have the event handler raise the event again. Unless you have 2 methods named OnNoGatewayCompleted (I'm hoping not)
objNoGateway.NoGatewayCompletedEvent
+= new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);
If you're looking for the waitHandles to be signalled in the event handler, shouldn't the methods OnCalledNumberBlockedCompleted be hooked up to the event instead.
PS: As Marc pointed out.. use WaitHandle.WaitAll ( the for loop demands that the async operations complete in order which may not be the case )
Use WaitHandle.WaitAny(handleArray); to wait on all the handles in the handle array instead of handle.WaitOne(); in a loop

Categories

Resources