C# object reference gets SOMETIMES lost in Threads that end via EventHandler - c#

I have a strange problem with following code, that is started about every minute.
Normally everything works fine, but sometimes the HandleCalcStatistikMarkersDone function raises an error because of a NullReferenceException.
I try to explain with the code:
I have a class Strategies. This class is started about every minute to calculate and update some information in a MySQL database. This class is instantiated multiple times in separate threads within a ticker on a form.
public partial class mainForm: Form
{
//do something including ticker, that starts RunStatistik about every minute after the previous thread ended
private void RunStatistik()
{
foreach (InternalObject objPar in InternalObjects)
{
Strategies.StrategyParameter giveParms = new Strategies.StrategyParameter();
giveParms.pair= objPar.pair;
Strategies strat = new Strategies();
Thread calcStatistikThread = new Thread(new ParameterizedThreadStart(strat.CalcCoinStatistik));
calcStatistikThread.Start(giveParms);
}
}
}
Internally in the upper initiated Strategies thread, there are stared some additional threads.
Those threads have a "DoneEvent" which is raised at the end of the function.
To notice, that all threads have ended before the main thread ends, I collect all subthreads in a List CalcStatistikMarkersThreads and wait until the list is empty.
The subthreads should remove themselves out of the upper List via the ThreadDone event.
But sometimes the searched thread (CalcStatistikMarkersThreads.Find) is not found anymore and I get a NullReferenceException.
The question is why?!
Could you tell me, why? And possibly how to prevent?
Thanks in advance.
class Strategies
{ public event EventHandler ThreadDone;
private List<Thread> CalcStatistikMarkersThreads;
//do something
public void CalcCoinStatistik(object parameters)
{
StrategyParameter givenParms = (StrategyParameter)parameters;
Pair internalPair = givenParms.pair
//do something
if (CalcStatistikMarkersThreads == null)
{
CalcStatistikMarkersThreads = new List<Thread>();
}
foreach (InternalTodo in InternalToDos)
{
Strategies strat = new Strategies();
CalcStatistikMarkersParameter csp = new CalcStatistikMarkersParameter();
csp.parm1 = param;
strat.ThreadDone += HandleCalcStatistikMarkersDone;
Thread candleCalc = new Thread(new ParameterizedThreadStart(strat.CalcStatistikMarkers));
CalcStatistikMarkersThreads.Add(candleCalc);
candleCalc.Start(csp);
while (CalcStatistikMarkersThreads.Count != 0)
{
Task.Delay(1000).Wait();
}
}
}
public void CalcStatistikMarkers(object parm)
{
//do something
if (ThreadDone != null)
ThreadDone(this, new ThreadInfoEventArgs(Thread.CurrentThread.ManagedThreadId));
}
public void HandleCalcStatistikMarkersDone(object sender, EventArgs e)
{
Guid workGUID = Guid.NewGuid();
ThreadInfoEventArgs tEv = (ThreadInfoEventArgs)e;
Thread currentThread;
try
{
currentThread = CalcStatistikMarkersThreads.Find(xy => xy.ManagedThreadId == tEv.ThreadID);
//HERE THE NullReferenceException is raised sometimes
CalcStatistikMarkersThreads.Remove(currentThread);
}
catch (Exception ex)
{
throw ex;
}
}
public class ThreadInfoEventArgs : EventArgs
{
private int threadID;
public ThreadInfoEventArgs(int trID)
{
this.threadID = trID;
}
public int ThreadID
{
get { return threadID; }
}
}
}
Cheers
Air

Related

c# Using an action from GUI while running thread

Question :
I'm a beginner in c# and i'm having a bit of trouble to understand how thread works with a form. I'm trying to update a progressbar when my program hit keypoints and i can't get it to work here is my code.
For my "worker" class :
public void addFollower(string followerName, Action<string> followerAction) {
this.followers.Add(followerName, followerAction);
}
private void notifyFollowers(string message) {
if (followers.Count > 0) {
foreach (String followerName in followers.Keys) {
followers[followerName].Invoke(message);
}
}
}
for my linking class (controller maybe?) :
public void runWithParams(Dictionary<string,string> parameters, Action<string> updateManager = null){
string app = parameters["appName"];
string navigator = parameters["navigatorName"];
string mode = parameters["mode"];
string scenario = parameters["scenarioName"];
try {
Scenario sc = this.scenarioBuilders[app].buildScenario(scenario);
if(updateManager != null) sc.addFollower("updateManager", updateManager);
Thread TestRunner = new Thread(sc.run);
TestRunner.Start();
} catch (Exception ex) {
Console.WriteLine(ex.Message);
Console.WriteLine("Unexpected shutdown or driver unreachable");
}
}
For the gui :
private void ButtonRun_Click(object sender, EventArgs e) {
Dictionary<string, string> parameters = new Dictionary<string, string>{
{"appName",this.CBApplicationChoice.SelectedItem.ToString()},
{"navigatorName",this.CBNavigatorChoice.SelectedItem.ToString()},
{"mode",this.CBModeChoice.SelectedItem.ToString()},
{"scenarioName",this.CBScenarioChoice.SelectedItem.ToString()}
};
this.dispatcher.runWithParams(parameters, ManageRealTimeStep1);
}
public void ManageRealTimeStep1(string liveevent){
if (liveevent.Contains("NumberOfPages")) {
this.PBStep1.Maximum = Convert.ToInt32(liveevent.Split(':')[1]);
} else if (liveevent.Contains("StartingTestNewPage")) {
this.PBStep1.Increment(1);
}
}
I'm getting an InvalidOperationException when i click on the RunButton and the error says that i'm trying to call a function that is in another thread. How can i fix it?
Thanks in advance for any answer/ insights
Solution :
I changed the method in gui for :
public void ManageRealTimeStep1(string liveevent) {
BeginInvoke(new Action(() => {
if (liveevent.Contains("NumberOfPages")) {
this.PBStep1.Maximum = Convert.ToInt32(liveevent.Split(':')[1]);
} else if (liveevent.Contains("StartingTestNewPage")) {
this.PBStep1.Increment(1);
}
}));
}
Use BeginInvoke method:
BeginInvoke(new Action(() =>
{
this.PBStep1.Maximum = Convert.ToInt32(liveevent.Split(':')[1]);
}));
Read more about updating WinForms UI from another thread here
You are not allowed to update the GUI from a different thread, see How to update the GUI from another thread in C#?.
You are accessing the GUI from the ManageRealTimeStep1 method which is used by the Scenario class (as a callback) on the background thread.

User interaction in non-UI thread?

in my WPF - C# application, I have a time consuming function, which I execute with a BackgroundWorker. The job of this function is to add given data from a file into a database. Now and then, I need some user feedback, for example the data is already in the store and I want to ask the user, whether he wants to merge the data or create a new object or skip the data completely. Much like the dialog windows shows, if I try to copy a file to a location, where a file with the same name already exists.
The problem is, that I cannot call a GUI-window from a non GUI-thread. How could I implement this behavior?
Thanks in advance,
Frank
You could work with EventWaitHandle ou AutoResetEvent, then whenever you want to prompt the user, you could the signal UI, and then wait for the responde. The information about the file could be stored on a variable.
If possible... my suggestion is to architect your long running task into atomic operations. Then you can create a queue of items accessible by both your background thread and UI thread.
public class WorkItem<T>
{
public T Data { get; set; }
public Func<bool> Validate { get; set; }
public Func<T, bool> Action { get; set; }
}
You can use something like this class. It uses a queue to manage the execution of your work items, and an observable collection to signal the UI:
public class TaskRunner<T>
{
private readonly Queue<WorkItem<T>> _queue;
public ObservableCollection<WorkItem<T>> NeedsAttention { get; private set; }
public bool WorkRemaining
{
get { return NeedsAttention.Count > 0 && _queue.Count > 0; }
}
public TaskRunner(IEnumerable<WorkItem<T>> items)
{
_queue = new Queue<WorkItem<T>>(items);
NeedsAttention = new ObservableCollection<WorkItem<T>>();
}
public event EventHandler WorkCompleted;
public void LongRunningTask()
{
while (WorkRemaining)
{
if (_queue.Any())
{
var workItem = _queue.Dequeue();
if (workItem.Validate())
{
workItem.Action(workItem.Data);
}
else
{
NeedsAttention.Add(workItem);
}
}
else
{
Thread.Sleep(500); // check if the queue has items every 500ms
}
}
var completedEvent = WorkCompleted;
if (completedEvent != null)
{
completedEvent(this, EventArgs.Empty);
}
}
public void Queue(WorkItem<T> item)
{
// TODO remove the item from the NeedsAttention collection
_queue.Enqueue(item);
}
}
Your UI codebehind could look something like
public class TaskRunnerPage : Page
{
private TaskRunner<XElement> _taskrunner;
public void DoWork()
{
var work = Enumerable.Empty<WorkItem<XElement>>(); // TODO create your workItems
_taskrunner = new TaskRunner<XElement>(work);
_taskrunner.NeedsAttention.CollectionChanged += OnItemNeedsAttention;
Task.Run(() => _taskrunner.LongRunningTask()); // run this on a non-UI thread
}
private void OnItemNeedsAttention(object sender, NotifyCollectionChangedEventArgs e)
{
// e.NewItems contains items that need attention.
foreach (var item in e.NewItems)
{
var workItem = (WorkItem<XElement>) item;
// do something with workItem
PromptUser();
}
}
/// <summary>
/// TODO Use this callback from your UI
/// </summary>
private void OnUserAction()
{
// TODO create a new workItem with your changed parameters
var workItem = new WorkItem<XElement>();
_taskrunner.Queue(workItem);
}
}
This code is untested! But the basic principle should work for you.
Specifically to your case
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(1000);
var a = Test1("a");
Thread.Sleep(1000);
var b = (string)Invoke(new Func<string>(() => Test2("b")));
MessageBox.Show(a + b);
}
private string Test1(string text)
{
if (this.InvokeRequired)
return (string)this.Invoke(new Func<string>(() => Test1(text)));
else
{
MessageBox.Show(text);
return "test1";
}
}
private string Test2(string text)
{
MessageBox.Show(text);
return "test2";
}
Test2 is a normal method which you have to invoke from background worker. Test1 can be called directly and uses safe pattern to invoke itself.
MessageBox.Show is similar to yourForm.ShowDialog (both are modal), you pass parameters to it (text) and you return value (can be a value of property of yourForm which is set when form is closed). I am using string, but it can be any data type obviously.
From the input of the answers here, I came to the following solution:
(Mis)Using the ReportProgress-method of the Backgroundworker in Combination with a EventWaitHandle. If I want to interact with the user, I call the ReportProgress-method and setting the background process on wait. In the Handler for the ReportProgress event I do the interaction and when finished, I release the EventWaitHandle.
BackgroundWorker bgw;
public MainWindow()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
bgw.WorkerReportsProgress = true;
bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged);
}
// Starting the time consuming operation
private void Button_Click(object sender, RoutedEventArgs e)
{
bgw.RunWorkerAsync();
}
// using the ProgressChanged-Handler to execute the user interaction
void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
UserStateData usd = e.UserState as UserStateData;
// UserStateData.Message is used to see **who** called the method
if (usd.Message == "X")
{
// do the user interaction here
UserInteraction wnd = new UserInteraction();
wnd.ShowDialog();
// A global variable to carry the information and the EventWaitHandle
Controller.instance.TWS.Message = wnd.TextBox_Message.Text;
Controller.instance.TWS.Background.Set();
}
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show(e.Result.ToString());
}
// our time consuming operation
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(2000);
// need 4 userinteraction: raise the ReportProgress event and Wait
bgw.ReportProgress(0, new UserStateData() { Message = "X", Data = "Test" });
Controller.instance.TWS.Background.WaitOne();
// The WaitHandle was released, the needed information should be written to global variable
string first = Controller.instance.TWS.Message.ToString();
// ... and again
Thread.Sleep(2000);
bgw.ReportProgress(0, new UserStateData() { Message = "X", Data = "Test" });
Controller.instance.TWS.Background.WaitOne();
e.Result = first + Controller.instance.TWS.Message;
}
I hope I did not overlooked some critical issues. I'm not so familar with multithreading - maybe there should be some lock(object) somewhere?

Stopping a Specific Thread and Starting It Up Again From Windows Service

I want to know how to stop and restart a thread.
I create N amount of threads, depending on conditions returned from a database. These are long running processes which should never stop but should I get a critical error within the thread I want to completely kill the thread and start it up like new.
The code which I use currently to start the threads:
foreach (MobileAccounts MobileAccount in ReceiverAccounts)
{
Receiver rec = new Receiver();
ThreadStart starterParameters = delegate { rec.StartListener(MobileAccount); };
Thread FeedbackThread = new Thread(starterParameters);
FeedbackThread.Name = MobileAccount.FriendlyName;
FeedbackThread.Start();
Thread.Sleep(1000);
}
You can write your own listener and manage its thread within it.
something like:
public class AccountListener
{
private Thread _worker = null;
private MobileAccount _mobileAccount;
public AccountListener(MobileAccount mobileAccount)
{
_mobileAccount = mobileAccount;
}
protected void Listen()
{
try
{
DoWork();
}
catch (Exception exc)
{
}
}
protected virtual void DoWork()
{
Console.WriteLine(_mobileAccount);
}
public void Start()
{
if (_worker == null)
{
_worker = new Thread(Listen);
}
_worker.Start();
}
public void Stop()
{
try
{
_worker.Abort();
}
catch (Exception)
{
//thrad abort exception
}
finally
{
_worker = null;
}
}
}

WPF - Updating Label Content During Processing

Well I've tried several methods of getting this to work, background worker, Dispatcher.Invoke, threading within the called class and nothing seems, to work. The best solution so far is an Extension method which calls the invoke of the control. Also I've tried avoid passing the data for the label through my event classes and simply invoking within my processing code, however this made no difference.
In regards to the background component, I kept getting exceptions saying the background worker was busy, so I instantiated the class several times, however the label only visibly changed once the entire operation had been complete.
I've removed my previous code, here's everything that is relevant, as it seems the issue is difficult to resolve.
Method Being Called
private void TestUris()
{
string text = new TextRange(rtxturis.Document.ContentStart, rtxturis.Document.ContentEnd).Text;
string[] lines = Regex.Split(text.Remove(text.Length - 2), "\r\n");
foreach (string uri in lines)
{
SafeUpdateStatusText(uri);
bool result;
string modUri;
if (!uri.Contains("http://"))
{
modUri = uri;
result = StoreData.LinkUriExists(new Uri("http://" + modUri));
}
else
{
modUri = uri.Substring(7);
result = StoreData.LinkUriExists(new Uri(uri));
}
if (!result)
{
Yahoo yahoo = new Yahoo();
yahoo.Status.Sending += (StatusChange);
uint yahooResult = 0;
yahooResult = yahoo.ReturnLinkCount(modUri);
if (yahooResult > 1000 )
{ results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, 1000, "Will be processed", true)); }
else
{ results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, (int)yahooResult, "Insufficient backlinks", false)); }
}
else
{
results.Add(new ScrapeDetails(Guid.NewGuid(), modUri, 0, "Previously been processed", false));
}
}
foreach (var record in results)
{
dgvresults.Items.Add(record);
}
EnableStartButton();
}
Yahoo Class
public class Yahoo
{
/// <summary>
/// Returns the amount of links each Uri has.
/// </summary>
public uint ReturnLinkCount(string uri)
{
string html;
Status.Update(uri, false); //this is where the status is called
try
{
html = client.DownloadString(string.Format("http://siteexplorer.search.yahoo.com/search?p=http%3A%2F%2F{0}&fr=sfp&bwm=i", uri));
}
catch (WebException ex)
{
ProcessError(ex.ToString());
return 0;
}
return (LinkNumber(html));
}
Status Classes
public class StatusEventArgs : EventArgs
{
private string _message;
private bool _isidle;
public StatusEventArgs(string message, bool isidle)
{
this._message = message;
this._isidle = isidle;
}
public bool IsIdle
{
get { return _isidle; }
}
public string Message
{
get { return _message; }
}
}
public class Status
{
public Status()
{
}
// Declaring an event, with a custom event arguments class
public event EventHandler<StatusEventArgs> Sending;
// Some method to fire the event.
public void Update(string message, bool isIdle)
{
StatusEventArgs msg = new StatusEventArgs(message, isIdle);
OnUpdate(msg);
}
// The method that invokes the event.
protected virtual void OnUpdate(StatusEventArgs e)
{
EventHandler<StatusEventArgs> handler = Sending;
if (handler != null)
{
handler(this, e);
}
}
}
Method That Changes the labels Content
private void StatusChange(object sender, StatusEventArgs e)
{
if(!e.IsIdle)
{
lblstatus.Content = e.Message;
lblstatus.Foreground = StatusColors.Green;
lblstatus.Refresh();
}
else
{
lblstatus.Content = e.Message;
lblstatus.Foreground = StatusColors.Grey;
lblstatus.Refresh();
}
}
The Refresh static method called:
public static class ExtensionMethods
{
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Render , EmptyDelegate);
}
Another EDIT: Staring at my code for a bit longer, I've realised, that the foreach loop will execute really quickly, the operation which takes the time, is
yahooResult = yahoo.ReturnLinkCount(modUri);
Therefore I've declared the status class (which handles the event and invokes the label etc) and subscibed to it. I've gotten better results, although it still feels random, sometimes I see a couple of label updates, and sometimes one even though the exact same URI's are passed, so weird.
I hope there is sth. helpful...
private void button1_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(o =>
{
int result = 0;
for (int i = 0; i < 9999999; i++)
{
result++;
Dispatcher.BeginInvoke(new Action(() =>
{
this.label1.Content = result;
}));
Thread.Sleep(1);
}
});
}
SOLVED IT YES WOOHOOOOOOOO 3 days of testing, testing, testing.
I decided to start a new project just with the extension method above and a simply for loop to test UI update functionality. I started testing different DispatchPrioraties (tested them all).
Weirdly, I found the highest priorities were the worse, for example using Send didn't update the label at all, Render updated it twice on average. This was the weird behavior I was experiencing as I tried different priorities. I discovered Background:
The enumeration value is 4. Operations are processed after all other non-idle operations are completed.
Now this sounded exactly what I didn't want, as obviously the label should update during processing, hence why I never tried it. I'm guessing that once one of my method has been completed, before the next it called, the UI is updated. I'm find of guessing, but it 100% consistently updates correctly on two separate operations.
Thanks all.
Well this is going to sound stupid but you could just reference the forms namespace, and then you can do this
using System.Windows.Forms;
mylabel = "Start";
Application.doEvents();
myLabel = "update"
Application.doEvents();
now the problem using this would be you are using wpf but you can still reference forms and use this namespace. The other issue is what ever is in the que would execute directly to the ui. However this is the most simplistic way of doing label updates i could think of.
would it be easier/better to add the status info as a property on this object, and have it just fire property change notifications?
that way the label text (or whatever) could be bound to the property instead of having the async work try to update a label?
or add a method like this to update status if you have to update it?
void SafeUpdateStatusText(string text)
{
// update status text on event thread if necessary
Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate
{
lblstatus.Content = text;
}, null);
}
otherwise, i don't think we have enough details to help yet....
I hope this helps:
private delegate void UpdateLabelDelegate(DependencyProperty dp, object value);
public void UpdateLabelContent(Label label, string newContent)
{
Dispatcher.Invoke(new UpdateLabelDelegate(label.SetValue), DispatcherPriority.Background, ContentProperty, newContent);
}
Usage:
while (true)
{
UpdateLabelContent(this.lblStatus, "Next random number: " + new Random().Next());
Thread.Sleep(1000);
}

Is this a safe way to execute threads alternatively?

I would like to run code alternatively, so I could stop execution at any moment. Is this code safe?
static class Program
{
static void Main()
{
var foo = new Foo();
//wait for interaction (this will be GUI app, so eg. btnNext_click)
foo.Continue();
//wait again etc.
foo.Continue();
foo.Continue();
foo.Continue();
foo.Continue();
foo.Continue();
}
}
class Foo
{
public Foo()
{
new Thread(Run).Start();
}
private void Run()
{
Break();
OnRun();
}
protected virtual void OnRun()
{
for (var i = 0; i < 5; i++)
{
Console.WriteLine(i);
Break();
}
//do something else and break;
}
private void Break()
{
lock (this)
{
Monitor.Pulse(this);
Monitor.Wait(this);
}
}
public void Continue()
{
lock (this)
{
Monitor.Pulse(this);
Monitor.Wait(this);
}
}
}
Of course I know, that now the application will never ends, but that's not the point.
I need this, because I would like to present steps in some kind of an algorithm and describe what is going on in particular moment, and making everything in one thread would lead to many complications even when using small amount of loops in the code. For example those lines:
for (var i = 0; i < 5; i++)
{
Console.WriteLine(i);
Break();
}
should be then replaced with:
if (this.i < 5)
{
Console.WriteLine(i++);
}
And that is just a small example of what I want to present. The code will be more complicated than a dummy for loop.
I recommend you check out this blog post about implementing fibers.
Code (In case the site goes down.)
public class Fiber
{
private readonly Stack<IEnumerator> stackFrame = new Stack<IEnumerator>();
private IEnumerator currentRoutine;
public Fiber(IEnumerator entryPoint)
{
this.currentRoutine = entryPoint;
}
public bool Step()
{
if (currentRoutine.MoveNext())
{
var subRoutine = currentRoutine.Current
as IEnumerator;
if (subRoutine != null)
{
stackFrame.Push(currentRoutine);
currentRoutine = subRoutine;
}
}
else if (stackFrame.Count > 0)
{
currentRoutine = stackFrame.Pop();
}
else
{
OnFiberTerminated(
new FiberTerminatedEventArgs(
currentRoutine.Current
)
);
return false;
}
return true;
}
public event EventHandler<FiberTerminatedEventArgs> FiberTerminated;
private void OnFiberTerminated(FiberTerminatedEventArgs e)
{
var handler = FiberTerminated;
if (handler != null)
{
handler(this, e);
}
}
}
public class FiberTerminatedEventArgs : EventArgs
{
private readonly object result;
public FiberTerminatedEventArgs(object result)
{
this.result = result;
}
public object Result
{
get { return this.result; }
}
}
class FiberTest
{
private static IEnumerator Recurse(int n)
{
Console.WriteLine(n);
yield return n;
if (n > 0)
{
yield return Recurse(n - 1);
}
}
static void Main(string[] args)
{
var fiber = new Fiber(Recurse(5));
while (fiber.Step()) ;
}
}
"...this will be GUI app..."
Then you probably do not want and will not have sequential code like above in Main().
I.e. the main GUI thread will not execute a serial code like above, but generally be idle, repainting, etc. or handling the Continue button click.
In that event handler you may better use an Auto|ManualResetEvent to signal the worker to proceed.
In the worker, just wait for the event.
I would suggest that any time one considers using Monitor.Wait(), one should write code so that it would work correctly if the Wait sometimes spontaneously acted as though it received a pulse. Typically, this means one should use the pattern:
lock(monitorObj)
{
while(notYetReady)
Monitor.Wait(monitorObj);
}
For your scenario, I'd suggest doing something like:
lock(monitorObj)
{
turn = [[identifier for this "thread"]];
Monitor.PulseAll(monitorObj);
while(turn != [[identifier for this "thread"]])
Monitor.Wait(monitorObj);
}
It is not possible for turn to change between its being checked whether it's the current thread's turn to proceed and the Monitor.Wait. Thus, if the Wait isn't skipped, the PulseAll is guaranteed to awaken it. Note that the code would work just fine if Wait spontaneously acted as though it received a pulse--it would simply spin around, observe turn wasn't set for the current thread, and go back to waiting.

Categories

Resources