Run event handler in one permanent thread - c#

I have looked for solution, but found nothing.
In some class i have event
public class ClassWithEvent
{
public event Action<string> SomeEvent;
...
}
and this event has subscriber
public class SubscriberClass
{
public void SomeMethod(string value)
{
...
}
}
ClassWithEvent objectWithEvent = new ClassWithEvent();
SubscriberClass subscriberObject = new SubscriberClass();
objectWithEvent.SomeEvent += subscriberObject.SomeMethod;
Somewhere in main thread this event can be invoked.
if(SomeEvent != null)
SomeEvent(someString);
And when it is happened its handler has to run in second thread. But every time in the same thread, so this second thread has to be permanent and not be terminated after first execution.
Help me please to implement this.

Create a shared queue:
private BlockingCollection<string> queue = new BlockingCollection<string>();
Create your dedicated thread:
Thread thread = new Thread(HandleEvents);
thread.Start();
Process events on that thread:
private void HandleEvents()
{
foreach (string someValue in queue.GetConsumingEnumerable())
{
//Do stuff
}
}
Place items into the queue when the event is raised:
objectWithEvent.SomeEvent += (x) => queue.Add(x);
On shutdown complete the queue:
queue.CompleteAdding();

Well it's quite tricky but it should work.
You will need to create the permanent thread, for example by starting while(true) there, and a List of actions, which will be checked inside of this loop, something like this:
ConcurrentBag<Action> actions = new ConcurrentBag<Action>();
new Thread(
delegate()
{
while (true)
{
Action a;
if (actions.TryTake(out a))
a();
}
}
).Start();
And every time you want to rise the event just add the action to the List:
actions.Add(new Action(() => { SomeEvent("abc"); }));

Related

C#: How do I wait for an event to be set?

I want to write a synchronous test that calls into some asynchronous product tasks.
In the example below, DoSomething() is called by a separate thread, and then it sets the SomethingCompleted event.
In my test code, how do I wait for SomethingCompleted to be set?
public event Action<Result> SomethingCompleted;
public void DoSomething()
{
Something();
this.SomethingCompleted(new Result("Success"));
}
using (var evt = new ManualResetEvent()) {
Action<Result> handler = _ => evt.Set();
SomethingCompleted += handler;
evt.WaitOne();
SomethingCompleted -= handler; //cut object reference to help GC
}
If required you can unsubscribe from the event after the wait has completed. That way the event will not keep the delegate and closure instance alive.
You can extract this into a reusable helper method/extension.
// test case
public void Test()
{
var yourObj = new YourObj();
var done = false;
Result result;
yourObj.SomethingCompleted += (finalResult) => {
result=finalResult;
done=true;
};
yourObj.DoSomething();
while(!done) Thread.Sleep(200);
if(result != theExpectedResult) kaboom();
}
What about subscribing to an event and "polling" the lambda until result comes available? This should work.
You're using the wrong type of event. The event you're using is a callback. In the code you supplied, the delegates attached to the SomethingCompleted event are going to be called on the same thread as DoSomething.
What you want is thread synchronization, using an event like AutoResetEvent or ManualResetEvent, which have nothing to do with the framework/language-level event that you're using. You could do something like this:
void MainThreadProc()
{
// create thread synchronization event
using (var evt = new ManualResetEvent(false))
{
// start background operation
ThreadPool.QueueUserWorkItem(BackgroundThreadProc, evt);
// this line will block until BackgroundThreadProc sets the event
evt.WaitOne();
}
// resume main thread operations here
...
}
void BackgroundThreadProc(object o)
{
// get event from argument
var evt = (ManualResetEvent) o;
// do the deed
...
// set event to signal completion
evt.Set();
}
This is just one of a number of different ways to do this. Alternatives include Parallel LINQ or the Task Parallel Library (both of which are best used with parallel operations, not just a single background operation). If you don't want to block the main thread, look at BackgroundWorker.

C# how to stop thread in time?

I have an user control which include timer. When timer event run, it will call some threads.
User Control
class MyControl
{
public Timer iTime
{
get;
set;
}
Timer tmr;
public MyControl
{
tmr = new Timer();
}
// Some Properties
}
}
Main Form
class MyForm
{
Thread thd;
MyControl cls = new MyClass();
cls.iTime.Tick += new EventHandler(iTime_Tick);
void iTime_Tick(object sender, EventArgs e)
{
thd = new Thread(delegate() { doWork(1); });
thd.Start();
thd = new Thread(delegate() { doOtherJob(); });
thd.Start();
}
delegate void notif(int Param1);
void Job(int Param1)
{
if (this.InvokeRequired)
{
notif handler = new notif(notifParam);
this.Invoke(handler, new object[] { Param1 });
}
else
{
// Other Process
}
}
private void Logout()
{
cls.iTime.Stop();
cls.iTime.Enabled = false;
cls.iTime.Tick -= new EventHandler(iTime_Tick);
thd.abort();
thd.join();
}
}
How to terminate thread in timer ? When I unsubscribe timer event even close form, the threads still run.
Disposing the form has no effect on your threads.
Your code is clearly incomplete (for example MyControl cls = new MyClass();, and we have no idea what doWork or doOtherJob are), but I suspect part of the problem is that you only have a single thread variable.
Every time the timer ticks, you do thd = new Thread twice. If your timer ticks ten times then thd is pointing at your most recent thread, but there are potentially 19 other threads still running, and any of those might be keeping your application alive.
One thing that might help is explicitly setting .IsBackground to true on the threads you create, since that will encourage them to terminate when your UI thread closes. However, I'd advise that creating this many threads in this way is likely not an efficient model, and you'd be better off revising your design to run just one or two worker threads, instead of kicking of dozens.

background/Asynchronous process using Threading or Delegate

At My website
1. After filling form Inserting that record in SQL database
2. In Next Line I take some class object then send to Matching with other record
3. In matching application taking so much time
Now I have decided I will put matching process in background/Asynchronous by using Threading or Delegate
My Previous code was:
1. Inserting all information in database
objclsBbDAL.InsertAcquirePrvider(objAcqProvBL);
2. Matching related record with other record in database
clsMatchMakingDAL objclsMatchMakingDAL = new clsMatchMakingDAL();
objclsMatchMakingDAL.AcquireMatch(objAcqProvBL);
Q 1. Which one is best way to run process in background/Asynchronous - Threading or Delegate
Now I am using Threading:
objclsBbDAL.InsertAcquirePrvider(objAcqProvBL);
//Threading
CallMatchMakingOnDiffThread(objAcqProvBL);
private void CallMatchMakingOnDiffThread(clsAcquireProviderBL objAcqPro)
{
clsMatchMakingDAL objclsMatchMakingDAL = new clsMatchMakingDAL();
Thread objThread = new Thread(() => objclsMatchMakingDAL.AcquireMatch(objAcqPro));
objThread.Start();
}
Q2. How can do this task with Delegate?
Delegates are like callbacks, you use them to notify that an asynchronous task has been completed, meaning the thread needs to call an event, which should have a delegate hooked onto it.
For example:
public struct ThreadData
{
public int handle;
public string details;
public ThreadData(int handle, string details)
{
this.handle = handle;
this.details = details;
}
}
public class ThreadWorker
{
private List<Thread> threads = new List<Thread>();
public int BeginAsyncWork(string details)
{
Thread thread = new Thread(new ParameterizedThreadStart(ThreadMethod));
threads.Add(thread);
thread.Start(new ThreadData(threads.Count - 1, details));
return threads.Count - 1;
}
private void ThreadMethod(object parameter)
{
ThreadData data = (ThreadData)parameter;
Console.WriteLine(data.details);
if (ThreadFinished != null) { ThreadFinished(data.handle); }
}
public delegate void ThreadEndDelegate(int handle);
public event ThreadEndDelegate ThreadFinished;
}
public static class Program
{
private static int[] handles;
public static void Main()
{
handles = new int[4];
ThreadWorker worker = new ThreadWorker();
worker.ThreadFinished += new ThreadWorker.ThreadEndDelegate(OnThreadFinished);
for (int i = 0; i < 4; i++)
{
handles[i] = worker.BeginAsyncWork("working: " + i);
}
Console.ReadKey();
}
private static void OnThreadFinished(int handle)
{
Console.WriteLine("thread: " + handle + " finished");
handles[handle] = 0;
}
}
It's long winded but it allows for full control over your threads.
EDIT:
Untested code. The shortest possible solution I could think of.
objclsBbDAL.InsertAcquirePrvider(objAcqProvBL);
//Threading
CallMatchMakingOnDiffThread(objAcqProvBL);
private void OnMatchAcquired(object match)
{
//do work with found match
}
private event Action<object> MatchAcquired = new Action<object>(OnMatchAcquired);
private void CallMatchMakingOnDiffThread(clsAcquireProviderBL objAcqPro)
{
clsMatchMakingDAL objclsMatchMakingDAL = new clsMatchMakingDAL();
Thread objThread = new Thread(
() => object match = (object)objclsMatchMakingDAL.AcquireMatch(objAcqPro); if(ThreadComplete!=nil){MatchAcquired(match);}
);
objThread.Start();
}
You can not do background processing with only a delegate.
A delegate is totally different from a thread or an asynchronous process.
You can understand a delegate as a pointer to a function.
Threads use delegates to execute a certain function but delegates alone are not any kind of background execution.
Doing what you mentioned up-there would run the process in background, but you have to know the costs for running the operation in background and in this way. You also need to know if it does really needs to be run in background or it only needs optimization.
The easyest way (for me at least) is to use a delegate and BeginInvoke, which will return immediately and for which you can supply a callback that is executed when the delegate is finished.
More info on MSDN.
In your sample code I do not see, that you need to be notified, when the operation is finished so you could do something like this:
new Action(() =>
{
clsMatchMakingDAL objclsMatchMakingDAL = new clsMatchMakingDAL();
objclsMatchMakingDAL.AcquireMatch(objAcqPro);
}).BeginInvoke(null, null);
This would execute the matching functionality on another thread that is managed by .Net for you. If you need to be notified on completion, then the first argument to the BeginInvoke call could be another delegate to handle the completion event.

Invoke event on MainThread from worker thread

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

BackgroundWorkerThread access in a thread

I use BackgroundWorker most of the time in the win form apps to show progress as I'm getting data. I was under impression that Work_completed is guaranteed to be executed on Main UI thread but it's not. If we create a thread and call the worker.RunWorkerAsync within it, it breaks if we try to update any gui control. Here is an example
private void StartButton_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ThreadStart(PerformWorkerTask));
_worker = new BackgroundWorker();
thread1.Start();
}
public void PerformWorkerTask()
{
_worker.DoWork += delegate
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
}
};
_worker.RunWorkerCompleted += delegate
{
// this throws exception
MessageLabel.Text = "Completed";
};
_worker.RunWorkerAsync();
}
How can we make backgroundworker work in this case?
RunWorkerAsync does its thread-synchronization magic by getting the SynchronizationContext from the thread that it is called on. It then guarantees that the events will be executed on the correct thread according to the semantics of the SynchronizationContext it got. In the case of the WindowsFormsSynchronizationContext, which is what is automatically used if you're using WinForms, the events are synchronized by posting to the message queue of the thread that started the operation. Of course, this is all transparent to you until it breaks.
EDIT: You MUST call RunWorkerAsync from the UI thread for this to work. If you can't do it any other way, your best bet is to invoke the beginning of the operation on a control so that the worker is started on the UI thread:
private void RunWorker()
{
_worker = new BackgroundWorker();
_worker.DoWork += delegate
{
// do work
};
_worker.RunWorkerCompleted += delegate
{
MessageLabel.Text = "Completed";
};
_worker.RunWorkerAsync();
}
// ... some code that's executing on a non-UI thread ...
{
MessageLabel.Invoke(new Action(RunWorker));
}
From your example it's hard to see what good the Thread (thread1) is, but if you really do need this thread1 then I think your only option is to use MainForm.Invoke() to execute RunWorkerAsync() (or a small method around it) on the main thread.
Added: You can use something like this:
Action a = new Action(_worker.RunWorkerAsync);
this.Invoke(a);
It sounds like the issue is just that you want to make a change to a GUI component and you aren't actually sure if you're on the GUI thread. Dan posted a valid method of setting a GUI component property safely, but I find the following shortcut method the simplest:
MessageLabel.Invoke(
(MethodInvoker)delegate
{
MessageLabel.Text = "Hello World";
});
If there are any issues with this approach, I'd like to know about them!
In the code you have presented here, you're adding the delegates for the BackgroundWorker events in a separate thread from the UI thread.
Try adding the event handlers in the main UI thread, and you should be okay.
You could probably make your existing code work by doing:
this.Dispatcher.BeginInvoke(() => MessageLabel.Text = "Completed")
instead of
MessageLabel.Text = "Completed"
You're probably having cross-thread data access issues, so you have to ensure that you access properties of MessageLabel on your UI thread. This is one way to do that. Some of the other suggestions are valid too. The question to ask yourself is: why are you creating a thread that does nothing other than create a BackgroundWorker thread? If there's a reason, then fine, but from what you've shown here there's no reason you couldn't create and start the BackgroundWorker thread from your event handler, in which case there would be no cross-thread access issue because the RunWorkerCompleted event handler will call its delegates on the UI thread.
I believe BackgroundWorker is designed to automatically utilize a new thread. Therefore creating a new thread just to call RunWorkerAsync is redundant. You are creating a thread just to create yet another thread. What's probably happening is this:
You create a new thread from thread 1 (the GUI thread); call this thread 2.
From thread 2, you launch RunWorkerAsync which itself creates yet another thread; call this thread 3.
The code for RunWorkerCompleted runs on thread 2, which is the thread that called RunWorkerAsync.
Since thread 2 is not the same as the GUI thread (thread 1), you get an illegal cross-thread call exception.
(The below suggestion uses VB instead of C# since that's what I'm more familiar with; I'm guessing you can figure out how to write the appropriate C# code to do the same thing.)
Get rid of the extraneous new thread; just declare _worker WithEvents, add handlers to _worker.DoWork and _worker.RunWorkerCompleted, and then call _worker.RunWorkerAsync instead of defining a custom PerformWorkerTask function.
EDIT: To update GUI controls in a thread-safe manner, use code like the following (more or less copied from this article from MSDN):
delegate void SetTextCallback(System.Windows.Forms.Control c, string t);
private void SafeSetText(System.Windows.Forms.Control c, string t)
{
if (c.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SafeSetText);
d.Invoke(d, new object[] { c, t });
}
else
{
c.Text = t;
}
}
The best way to deal with these generic problems is to deal it once. Here I'm posting a small class that wraps the backgroupdworker thread and makes sure that the workcompleted always gets executed on the UI thread.
using System.Windows.Forms;
namespace UI.Windows.Forms.Utilities.DataManagment
{
public class DataLoader
{
private BackgroundWorker _worker;
private DoWorkEventHandler _workDelegate;
private RunWorkerCompletedEventHandler _workCompleted;
private ExceptionHandlerDelegate _exceptionHandler;
public static readonly Control ControlInvoker = new Control();
public DoWorkEventHandler WorkDelegate
{
get { return _workDelegate; }
set { _workDelegate = value; }
}
public RunWorkerCompletedEventHandler WorkCompleted
{
get { return _workCompleted; }
set { _workCompleted = value; }
}
public ExceptionHandlerDelegate ExceptionHandler
{
get { return _exceptionHandler; }
set { _exceptionHandler = value; }
}
public void Execute()
{
if (WorkDelegate == null)
{
throw new Exception(
"WorkDelegage is not assinged any method to execute. Use WorkDelegate Property to assing the method to execute");
}
if (WorkCompleted == null)
{
throw new Exception(
"WorkCompleted is not assinged any method to execute. Use WorkCompleted Property to assing the method to execute");
}
SetupWorkerThread();
_worker.RunWorkerAsync();
}
private void SetupWorkerThread()
{
_worker = new BackgroundWorker();
_worker.WorkerSupportsCancellation = true;
_worker.DoWork += WorkDelegate;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error !=null && ExceptionHandler != null)
{
ExceptionHandler(e.Error);
return;
}
ControlInvoker.Invoke(WorkCompleted, this, e);
}
}
}
And here is the usage. One thing to note is that it exposes a static property ControlInvoker that needs to be set only once (you should do it at the beginning of the app load)
Let's take the same example that I posted in question and re write it
DataLoader loader = new DataLoader();
loader.ControlInvoker.Parent = this; // needed to be set only once
private void StartButton_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(new ThreadStart(PerformWorkerTask));
_worker = new BackgroundWorker();
thread1.Start();
}
public void PerformWorkerTask()
{
loader.WorkDelegate = delegate {
// get any data you want
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
}
};
loader.WorkCompleted = delegate
{
// access any control you want
MessageLabel.Text = "Completed";
};
loader.Execute();
}
Cheers

Categories