Presently, I have a windows form that is receiving data from a named pipe asynchronously. To avoid getting the "Cross thread operation not valid: Control 'myTextBox' accessed from a thread other than the thread it was created on" I am using an anonymous method (see http://www.codeproject.com/Articles/28485/Beginners-Guide-to-Threading-in-NET-Part-of-n):
// Pass message back to calling form
if (this.InvokeRequired)
{
// Create and invoke an anonymous method
this.Invoke(new EventHandler(delegate
{
myTextBox.Text = stringData;
}));
}
else
myTextBox.Text = stringData;
My question is, what does the "new EventHandler(delegate" line do? Does it create a delegate of a delegate? Could someone please explain, how would I implement the above functionality using a named delegate instead (just to help with understanding it)? TIA.
If you have a C++ background, I'd describe delegates as simple pointers to functions. Delegates are .NET's way of safely handling function pointers.
To used a named delegate, you first have to create a function to handle the event:
void MyHandler(object sender, EventArgs e)
{
//Do what you want here
}
Then, for your previous code, change it to this:
this.Invoke(new EventHandler(MyHandler), this, EventArgs.Empty);
If I were doing this though, I'd write it like this to avoid duplicate code.
EventHandler handler = (sender, e) => myTextBox.Test = stringData;
if (this.InvokeRequired)
{
this.Invoke(handler, this, EventArgs.Empty); //Invoke the handler on the UI thread
}
else
{
handler(this, EventArgs.Empty); //Invoke the handler on this thread, since we're already on the UI thread.
}
Related
Background
I'm writing a c# wrapper for a node.js application. In this wrapper I continuously read the standard output via Process.RedirectStandardOutput. The event is bound to the function onOutputDataReceived, in an instance of the class ProcessManager. In this same instance, there is also an instance of a custom event system.
[ProcessManager]
EventSystem eventSystem;
private void Start()
{
[...]
process.OutputDataReceived += onOutputDataReceived;
[...]
}
private void onOutputDataReceived(object sender, DataReceivedEventArgs e)
{
[...]
eventSystem.call(eventName, args);
}
[EventSystem]
List<EventHandler> eventList;
public Boolean call(String eventName, dynamic args)
{
[...]
foreach (EventHandler handler in eventList)
{
handler(args);
}
[...]
}
The problem occurs when the event is being called. Here is an example from a winforms application using my wrapper.
Wrapper.ProcessManager procMan;
procMan.eventSystem.on(eventName, (a) =>
{
button1.Text = someValue;
});
When run, the application crashes with the message
Cross-thread operation not valid: Control 'button1' accessed from a thread other than the thread it was created on
My issue, as I understand it, is this:
onOutputDataReceived is being executed asynchronously, in its own thread. As this same thread, only meant to be handling the output, goes on to call the events, I'm unintentionally multithreading my wrapper, making life harder for anyone implementing it.
Basically,
I need to run the line eventSystem.call() in the same thread that maintains the rest of the ProcessManager instance, as soon as new output data has been received as possible. Any ideas on how this best can be achieved?
A solution I've thought of is something like this
[ProcessManager]
Queue<string> waiting = new Queue<string();
EventSystem eventSystem;
private void onOutputDataReceived(object sender, DataReceivedEventArgs e)
{
[...]
waiting.Enqueue(eventName);
}
private void WhenReady()
{
while(waiting.Count > 0)
eventSystem.call(waiting.Dequeue());
}
As far as I can see, this would involve some kind of polling every x milliseconds, which doesn't feel like a clean solution. Also, it seems to me as if such a solution would be way too expensive for when no messages are being received and too slow for when some are.
The code that executes the nodejs process and reads its output should not need to know about the threading requirements of event subscribers. Make the subscriber satisfy its own requirements:
(a) =>
{
Invoke(new Action(() => button1.Text = someValue)); //marshal to UI thread
}
Your tentative solution would not work because it would block the UI thread.
Also, waiting is being used in an unsynchronized way... This is an unrelated bug.
I'm having trouble invoking an event from a secondary thread in the main thread. The event handler is not executed on main thread. Can anyone give me some pointers on what I'm doing wrong.
Thanks
namespace ThreadSyncExample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("MainThread: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
Execute execThe = new Execute();
execThe.FinishedThread += (src, arg) =>
{
//This shoould be executed on MainThread right?
Console.WriteLine("Thread Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
};
execThe.Run();
Console.ReadKey();
}
}
class Execute
{
public void Run()
{
Thread exec = new Thread(() =>
{
Console.WriteLine("Worker Thread : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
OnFinishedThread();
});
exec.Start();
}
public event EventHandler FinishedThread;
protected virtual void OnFinishedThread()
{
if (null != FinishedThread)
{
EventArgs args = new EventArgs();
FinishedThread(this, EventArgs.Empty);
}
}
}
}
C# events are basically just an easy-to-use collection of delegates and "firing" an event just causes the runtime to loop through all of the delegates and fire them one at a time.
So your OnFinishedThread event handler is getting called on the Worker thread.
If you want your event on the main thread, you have to Invoke() it.
EDIT :
It appears that you don't have access to forms, or WPF (so you don't have access to Invoke() either)
So you have to manually marshall the call to the main thread by thread synchronization process. It's generally a pain.
Probably the easiest solution would be to simply use a BackgroundWorker because this way you no longer need to manualy marshal the calls to the main thread.
var worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
// call the XYZ function
e.Result = XYZ();
};
worker.RunWorkerCompleted += (sender, e) =>
{
// use the result of the XYZ function:
var result = e.Result;
// Here you can safely manipulate the GUI controls
};
worker.RunWorkerAsync();
the FinishedThread() event handler will be executed on the same thread as Execute.Run() is executed on. Just because you defined the body of the FinishedThread event handler in main() doesn't mean that main() somehow defines it's execution context.
Some mechanisms you can use to perform thread marshalling:
Use a system.windows.forms.control and use the Invoke method to marshal a function call back to the thread the control was created on. Under the hood, this will use features of the Windows Message Loop to handle the actual marshal
Use synchronization primitives to handle the marshalling manually.
Rather than re-iterate what has already been stated, check this answer for more information on marshalling:
Marshall to a thread manually
Hi i have some question related to call back feature in libraries created by user in c#
i have created a winform application named "Sample"
i have also created a class library named "Library"
Sample contains only one form that has a button say "CALL"
i have implemented all the coding part in a library
when i click on the call button on form then a method "ACTIVATE CALL" of the library is called.
this method performs some work on a thread.
What i want is when thread work if finished then "CALLBACK" method placed in my winform must be called.
To achieve this i have passed "this" reference of the form to the library
i collected "this" as obj "Object" type in formal arguement in library.
can anybody suggest me how to call callback method?
i tried this:
if(obj.GetType()== typeOf(what to specify here))
{
obj.callback();
}
hope somebody can provide me help.
note: both library and sample are different projects
how to achieve callback feature?
Define your library method with a callback.
public void ACTIVATE(object arg, object arg, Action callback)
{
// Do what you have to do here.
callback.Invoke();
}
Then, in your Sample WinForms client you can call something like this.
public void MethodInSample()
{
Library lib = new Library();
Action callback = () => { DoSomethingHere };
Lib.ACTIVATE(1,1,callback);
}
If you want the callback to return some parameters, you could use a Func<> instead and define the arguments that way.
Alternatively, you could use an event. The BackgroundWorker object is a good example of this. This class has a method called RunWorkerAsync(), which causes some work to be done on a background thread. There is then an event called RunWorkerCompleted which you listen on to indicate when the background thread has completed.
Both methods are valid I think, but the second has the benefit of allowing more than one party to listen for completion of the work.
Have the user of the ActivateCall function supply a callback so in you library:
function void ActivateCall(Action callback){
//Do Stuff
if (null != callback){
callback();
}
}
and then in your main form:
function button1_Click(object sender, EventArgs e){
library.ActivateCall(DoStuff);
}
There are a number of things to look out for though since you say you are doing stuff in a separate thread within the library call. If you are altering the GUI at all in the callback you will need to make sure you do the work in the GUI thread. You will also need to make sure you run the callback once all the work in the thread has been completed (I suspect).
To make sure your callback is run in the GUI thread (if required) do something like this:
function button1_Click(object sender, EventArgs e){
library.ActivateCall(DoStuff());
}
function void DoStuff(){
if (InvokeRequired(){
Invoke(DoStuff);
return;
}
//Do stuff here....
}
Finally i achieved this using Delegate+Event
*****************Sample class**************************
call()
{
//activate method of library is called
libraryObject.stop += new LibraryClass.callback(setCallbackMethod);
libraryObject.activate();
}
public void setCallbackMethod(String str)
{
// most important to be back on main thread
this.Invoke((MethodInvoker)delegate
{
btn.Enabled = true;
});
}
*******************Library***************************
public delegate void callback(String str);
public event callback stop;
activate()
{
//instantiates a thread/timer
aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(CheckForMessage);
aTimer.Interval = 1000;
aTimer.Start();
}
public void CheckForMessage(object source, ElapsedEventArgs e)
{
//performs some work
//calls callback method of ui thread in sample code
if (stop != null)
{
stop("COMPLETED");
}
}
I have a worker thread that needs to add items to a BindingList. However, the BindingList is databound to a DataGridView. So, when I try to add to the list, I get an InvalidOperationException (Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.)
Normally for this exception you would do:
if(winformControl.InvokeRequired) {
winformControl.Invoke(MethodDelegate);
}
However, the databinding confuses things, as there is no Winform control in sight. All I have is the following line, which throws the exception:
ClassInstance.MyBindingList.Add(myObject);
If you have a solution specifically for this scenario, great.
If not, how can I get the worker thread to tell my main thread to perform a particular method (with several parameters supplied by the worker thread)? This may be a preferable option, since my worker thread is actually doing a bunch of stuff at the moment (like writing to the database), and I'm not sure if everything is thread-safe. I'm a student, and new to multithreading, and it really is not my forte yet.
One option here is to tell BindingList<T> to use the sync-context, like this - however, this is arguably not the best approach. I wonder if you could expose your data via an event or similar (rather than adding to the list directly) - then have your UI handle the event by sending to the right thread and adding to the UI model.
In your worker class constructor, try this:
private System.Threading.SynchronizationContext mContext = null;
/// <summary>
/// Constructor for MyBackgroundWorkerClass
/// </summary>
public MyBackgroundWorkerClass(System.Threading.SynchronizationContext context)
{
mContext = context;
}
Then, when you need to invoke something on the UI thread:
private void CallOnTheUiThread(object dataToPassToUiThread)
{
// Make sure the code is run on the provided thread context.
// Make the calling thread wait for completion by calling Send, not Post.
mContext.Send(state =>
{
// Change your UI here using dataToPassToUiThread.
// Since this class is not on a form, you probably would
// raise an event with the data.
}
), null);
}
When creating your worker class from a form on the UI thread, this is what you would pass as the synchronization context.
private void Form1_Load(object sender, EventArgs e)
{
var worker = new MyBackgroundWorkerClass(SynchronizationContext.Current);
}
You can fire an event to the main, UI, thread and there have:
if (this.InvokeRequired)
{
this.Invoke(...);
}
so you are testing on the main Window itself.
BackgroundWorkers are easy to implement if you are able to given the requirements.
Define a DoWork method that runs on a background thread such as saves to the database. The RunWorkerCompleted method is called when DoWork finishes. RunWorkerCompleted runs on the UI thread, and you can update the view's list with no problems.
// on the UI thread
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += RunWorkerCompleted;
worker.RunWorkerAsync("argument");
Events:
static void DoWork(object sender, DoWorkEventArgs e)
{
e.Result = "4";
}
static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
string a = (string)e.Result;
Console.WriteLine(a);
}
else
{
Console.WriteLine(e.Error.Message);
}
}
I have a method. I want to return a value not from the main thread but from separate thread. Can you give example of it?
Easiest way is to check out the Background Worker
//set up your BackgroundWorker
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result != null)
{
//process your e.Result
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do your work here
e.Result = "testing"; //set the result to any object
}
Your question does not make sense. A method returns a value directly to the method that called it, on the same thread.
EDIT: If you want a method to supply a value to the UI thread on WinForms, you can call the BeginInvoke method. For example,
//In some event handler, such as button1_Click:
ThreadPool.QueueUserWorkItem(delegate {
//This code runs on a background thread.
//In it, you can do something that takes
//a long time without freezing the UI. If
//you need to interact with the UI from
//the background thread, use the Invoke
//method, like this:
var text = (string)Invoke(new Func<string>(() => textBox1.Text));
//I assume you'd want to do something more meaningful.
var result = text + Environment.NewLine + new String(text.Reverse().ToArray());
//To send the result back to the UI thread, call BeginInvoke:
BeginInvoke(new Action(delegate {
//This code is back on the UI thread,
//but it can still use the variables
//defined earlier.
label1.Text = result;
});
});
Jon Skeet has an excellent article on threading within .net in general. However, if you would like a more specific answer to a more specific problem, please post more details.
EDIT:
To make have methods return in a thread other than the main thread, all you need is a second thread. Everything done in that thread will be method calls and returns in that separate thread. Passing data between threads is a much more complex and trick subject. As a starting point, again I point to Jon Skeet's article to get a good base understanding. Beyond that, there are general principles that can be helpful, like Asynchronous calls and BackgroundWorkers (also see here)that can be very helpful, but these are only options, there many ways to do this, and how it should be done is very dependent on the situation.
In order for your method to return something from another thread, that other thread must "have" the something, and must indicate that the "something" is ready to be returned. There is no general case of this, but there are specific cases. For instance, a producer/consumer problem where your other thread produces something and puts it into a queue, and the first thread waits until there's something in the queue, takes it out, then returns it.
Another case that makes a little sense is seen in asynchronous ASP.NET pages. The page starts its life normally, issues one or more asynchronous operations, and then returns back to ASP.NET. It does nothing else until all the asynchronous operations have completed. Then, ASP.NET calls a method in the page that retrieves the results of these operation and uses them in the rest of the page.
You may be able to see that these two cases are very different. That's because you seem to have asked a "learning" question that amounts to "I wonder if a method always has to get its return value from the same thread?" But that's not something you ever have to do in real life, not really.
I will add that the Ada programming language includes something like this - someone who's actually used it will have to say whether it was useful. If I recall correctly, one task can rendezvous with another, and pass data between them.
This does what you asked for:
class DoSomething
{
string result;
public void RunAsync()
{
var t = new BackgroundWorker();
t.DoWork += (sender, e) =>
{
result = string.Empty; // your code goes here instead of string.empty
};
t.RunWorkerCompleted += Finished;//BackgroundWorkerFinished(sender, e);
t.RunWorkerAsync();
}
public void Finished(object sender, RunWorkerCompletedEventArgs e)
{
//result has been set, now what?
}
}
Once you get that down this becomes more useful:
public static void RunAsync(this Action ActionToAsync, Action<object, RunWorkerCompletedEventArgs> FinishedAction)
{
var t = new BackgroundWorker();
t.DoWork += (sender, e) => ActionToAsync();
t.RunWorkerCompleted += (sender, e) => FinishedAction.Invoke(sender,e);//BackgroundWorkerFinished(sender, e);
t.RunWorkerAsync();
}