ThreadA spawns ThreadB.
ThreadB throws an exception.
How can ThreadA know about this exception?
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ThreadStart threadDelegate1 = new ThreadStart(MyClass1.DoThis);
Thread ThreadA = new Thread(threadDelegate1);
ThreadA.Start();
Thread.Sleep(100000); // this thread is doing something else here, sleep simulates it
}
}
class MyClass1
{
public static void DoThis()
{
try
{
ThreadStart threadDelegate1 = new ThreadStart(MyClass2.DoThat);
Thread ThreadB = new Thread(threadDelegate1);
ThreadB.Start();
Thread.Sleep(100000); // this thread is doing something else here, sleep simulates it
}
catch (Exception e)
{
// I want to know if something went wrong with MyClass2.DoThat
}
}
}
class MyClass2
{
public static void DoThat()
{
throw new Exception("From DoThat");
}
}
}
Here is one way, using ManualResetEvent and lambdas:
try
{
Exception exc;
using (ManualResetEvent resetEvent = new ManualResetEvent(false))
{
Thread ThreadB = new Thread(() =>
{
try
{
MyClass2.DoThat();
}
catch (Exception e)
{
exc = e;
resetEvent.Set();
}
});
ThreadB.Start();
if (resetEvent.WaitOne(10000))
{
throw exc;
}
}
}
catch (Exception e)
{
// I want to know if something went wrong with MyClass2.DoThat
}
You can clean this up, surely depending on what you want to do specifically.
As long as your thread is sleeping it cannot be interrupted by an exception caused by another thread. If you can control how your thread is doing something else he should be waiting in an alertable mode where the does e.g. wait for a threadExceptionEvent.
If you do not have control how your thread is waiting the best thing you can do is to check in the times between your thread did something for e.g. a bool exception flag and throw this one.
The following code shows how you can wait for several WaitHandles at once and react depending on the fired event appropriately.
using System;
using System.Threading;
class Program
{
static AutoResetEvent _ExceptionEvent = new AutoResetEvent(false);
static WaitHandle _SomeEvent = new AutoResetEvent(false);
static WaitHandle[] _Waiters = new WaitHandle[] { _ExceptionEvent, _SomeEvent };
static Exception _LastThrownException = null;
static int _CatchedExCount = 0;
static void ThreadA()
{
while (true)
{
int eventIdx = WaitHandle.WaitAny(_Waiters);
if (eventIdx == 0) // Exception event
{
Exception lastEx = Interlocked.Exchange(ref _LastThrownException, null);
if (lastEx != null)
{
Console.WriteLine("Thread A got exception {0}", lastEx.Message);
_CatchedExCount++;
//throw lastEx;
}
}
}
}
static void ThreadB()
{
while (true)
{
try
{
ThreadBWorker();
}
catch (Exception ex)
{
// Do not overwrite a pending exception until it was processed
Exception old = null;
do
{
old = Interlocked.CompareExchange(ref _LastThrownException, ex, null);
if( old != null) // wait a bit to allow processing of existing exception
{
Thread.Sleep(1);
}
}
while (old != null);
_ExceptionEvent.Set();
}
}
}
static int _exCount = 0;
static void ThreadBWorker()
{
throw new Exception("Thread B Exception " + _exCount++);
}
static void Main(string[] args)
{
Thread t2 = new Thread(ThreadB);
t2.Start(); // start producing exception
Thread t1 = new Thread(ThreadA);
t1.Start(); // wait for exceptions
}
}
Yours,
Alois Kraus
Related
I'm using a constrained execution region (CER) to protect the section of code within a while loop of a thread:
private static void MyThreadFunc()
{
try {
...
while (true)
{
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
// do something not to be aborted
}
Thread.Sleep(1); // allow while loop to be broken out
}
}
catch (ThreadAbortException e)
{
// handle the exception
}
}
The problem is if I do not introduce the Thread.Sleep(1) statement at the end of the while loop, any attempt to call Thread.Abort() on the thread hangs. Is there any better method to abort the thread without using the Thread.Sleep() function?
I don't know why you need to abort the thread manually as CLR will do it once it's completed or use Thread.Join to wait until it terminates. But you can make use of the ManualResetEvent to abort it gracefully.
I have made few changes in the code by replacing the while(true) with the ManualResetEvent
class ThreadManager
{
private ManualResetEvent shutdown = new ManualResetEvent(false);
private Thread thread;
public void start ()
{
thread = new Thread(MyThreadFunc);
thread.Name = "MyThreadFunc";
thread.IsBackground = true;
thread.Start();
}
public void Stop ()
{
shutdown.Set();
if (!thread.Join(2000)) //2 sec to stop
{
thread.Abort();
}
}
void MyThreadFunc ()
{
while (!shutdown.WaitOne(0))
{
// call with the work you need to do
try {
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
// do something not to be aborted
}
}
catch (ThreadAbortException e)
{
// handle the exception
}
}
}
}
What is the proper way to create and dispose a system timer my code is as below
using System.Timers;
public void StartGetFileTimer(int interval)
{
if (TIMER_GET_FILE != null)
{
StopGetFileTimer();
}
try
{
if (TIMER_GET_FILE == null)
{
TIMER_GET_FILE = new Timer();
TIMER_GET_FILE.Interval = interval * 1000;
TIMER_GET_FILE.Elapsed += new ElapsedEventHandler(GetLatestFileTimer_tick);
TIMER_GET_LATEST_FILE.Enabled = true;
TIMER_GET_FILE.Start();
}
else
{
//log
}
}
catch (Exception e)
{
//log
}
}
public void StopGetFileTimer()
{
try
{
if (TIMER_GET_LATEST_FILE != null)
{
TIMER_GET_LATEST_FILE.Elapsed -= new ElapsedEventHandler(GetLatestFileTimer_tick);
TIMER_GET_LATEST_FILE.Stop();
TIMER_GET_LATEST_FILE.Enabled = false;
TIMER_GET_LATEST_FILE.Dispose();
TIMER_GET_LATEST_FILE = null;
}
}
catch (Exception ex)
{
//log
}
}
Simply use the Dispose method, but as the documentation says:
Callbacks can occur after the Dispose() method overload has been
called, because the timer queues callbacks for execution by thread
pool threads. You can use the Dispose(WaitHandle) method overload to
wait until all callbacks have completed.
The Dispose(WaitHandle) should be used like:
ManualResetEvent resetEvent = new ManualResetEvent(false);
Timer.Dispose(resetEvent);
resetEvent.WaitOne();
I have a class which contains a method for receiving UDP data in a separate thread. I do this to avoid the main application (which is running in Unity3D) from stalling.
I need to pass the data that is received in the separate thread to another class, which runs on the original thread and, as such, is able to interact with Unity3D.
Here is roughly what the UDPReceiver looks like:
public class UDPReciever {
//...
public UDPReciever() {
m_Port = 12345;
m_Worker = new Thread(new ThreadStart(recvData));
m_Worker.IsBackground = true;
m_Worker.Start();
}
void recvData() {
m_UDPClient = new UdpClient(m_Port);
while (true) {
try {
IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
byte[] data = (m_UDPClient.Receive(ref anyIP));
// TODO: Hand 'data' to NetworkController class (running in the original thread) for processing
} catch (Exception err) {
print(err.ToString());
}
}
}
}
This is roughly what the NetworkController class needs to look like. Ideally the "OnNewData" method would be called every time a new packet is received with the data passed as an argument.
public class NetworkController {
//...
void OnNewData(pData) {
// Process the data in this thread
}
}
How would I go about achieving this? Thanks in advance.
Here is how it could be done (not tested):
public class Dispatcher : MonoBehaviour
{
private static readonly BlockingCollection<Action> tasks = new BlockingCollection<Action>();
public static Dispatcher Instance = null;
static Dispatcher()
{
Instance = new Dispatcher();
}
private Dispatcher()
{
}
public void InvokeLater(Action task)
{
tasks.Add(task);
}
void FixedUpdate()
{
if (tasks.Count > 0)
{
foreach (Action task in tasks.GetConsumingEnumerable())
{
task();
}
}
}
}
...
NetworkController networkControllerInstance;
void recvData()
{
m_UDPClient = new UdpClient(m_Port);
while (true)
{
try
{
IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
byte[] data = (m_UDPClient.Receive(ref anyIP));
Dispatcher.Instance.InvokeLater(() => networkControllerInstance.OnNewData(data));
}
catch (Exception err)
{
print(err.ToString());
}
}
}
EDIT:
A version that should be compliant with .Net 3.5:
public class Dispatcher : MonoBehaviour
{
private static readonly Queue<Action> tasks = new Queue<Action>();
public static Dispatcher Instance = null;
static Dispatcher()
{
Instance = new Dispatcher();
}
private Dispatcher()
{
}
public void InvokeLater(Action task)
{
lock (tasks)
{
tasks.Enqueue(task);
}
}
void FixedUpdate()
{
while (tasks.Count > 0)
{
Action task = null;
lock (tasks)
{
if (tasks.Count > 0)
{
task = tasks.Dequeue();
}
}
task();
}
}
}
EDIT 2:
if you want to avoid freezing the main thread during a too long period:
void FixedUpdate()
{
if (tasks.Count != 0)
{
Action task = null;
lock (tasks)
{
if (tasks.Count != 0)
{
task = tasks.Dequeue();
}
}
task();
}
}
I want to know when all my async threads have completed so I know when to close my loading form. My code never closes the loading form. I don't know why. I'm unsure how to correctly pass my ManualResetEvent object to the async thread too.
I'm also open to a simpler means to achieve my goal of knowing when to close the loading form.
UPDATE
After reading the advice here I've updated my class. Unfortunetly, it still does not work. I feel closer though. It's just that the callback never fires.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Threading;
namespace BrianTests
{
public class TaskInfo
{
public RegisteredWaitHandle Handle;
public string OtherInfo = "default";
public Form loading;
}
public partial class AsyncControlCreateTest : Form
{
//List<ManualResetEvent> MREs = new List<ManualResetEvent>();
Form loading = new Form() { Text = "Loading...", Width = 100, Height = 100 };
CountdownWaitHandle cdwh;
public AsyncControlCreateTest()
{
InitializeComponent();
}
private void AsyncControlCreateTest_Load(object sender, EventArgs e)
{
loading.Show(this);//I want to close when all the async threads have completed
CreateControls();
}
private void CreateControls()
{
int startPoint= 0;
int threadCount = 2;
cdwh = new CountdownWaitHandle(threadCount);
for (int i = 0; i < threadCount; i++)
{
ManualResetEvent mre = new ManualResetEvent(initialState: true);
UserControl control = new UserControl() { Text = i.ToString() };
control.Load += new EventHandler(control_Load);
Controls.Add(control);
control.Top = startPoint;
startPoint += control.Height;
//MREs.Add(mre);
//mre.Set();//just set here for testing
}
Task.Factory.StartNew(new Action(() =>
{
TaskInfo info = new TaskInfo();
info.loading = loading;
try
{
info.Handle = ThreadPool.RegisterWaitForSingleObject(cdwh, WaitProc, info, 4000, executeOnlyOnce: false);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}));
}
public static void WaitProc(object state, bool timedOut)
{//this callback never occurs...
TaskInfo ti = (TaskInfo)state;
string cause = "TIMED OUT";
if (!timedOut)
{
cause = "SIGNALED";
// If the callback method executes because the WaitHandle is
// signaled, stop future execution of the callback method
// by unregistering the WaitHandle.
if (ti.Handle != null)
ti.Handle.Unregister(null);
}
Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.",
ti.OtherInfo,
Thread.CurrentThread.GetHashCode().ToString(),
cause
);
ti.loading.Close();
}
void control_Load(object sender, EventArgs e)
{
RichTextBox newRichTextBox = new RichTextBox();
UserControl control = sender as UserControl;
control.Controls.Add(newRichTextBox);
Task.Factory.StartNew(new Action(() =>
{
Thread.Sleep(2000);
newRichTextBox.Invoke(new Action(() => newRichTextBox.Text = "loaded"));
cdwh.Signal();
}));
}
}
public class CountdownWaitHandle : WaitHandle
{
private int m_Count = 0;
private ManualResetEvent m_Event = new ManualResetEvent(false);
public CountdownWaitHandle(int initialCount)
{
m_Count = initialCount;
}
public void AddCount()
{
Interlocked.Increment(ref m_Count);
}
public void Signal()
{
if (Interlocked.Decrement(ref m_Count) == 0)
{
m_Event.Set();
}
}
public override bool WaitOne()
{
return m_Event.WaitOne();
}
}
}
The problem is that WaitHandle.WaitAll is throwing an exception, which you can see:
try
{
WaitHandle.WaitAll(MREs.ToArray());
}
catch (Exception e) {
MessageBox.Show(e.Message);
throw;
}
The error message is that "WaitAll for multiple handles on a STA thread is not supported."
If you do something like
foreach(var m in MREs)
m.WaitOne();
It will work.
I'm not quite sure why the exception did not crash the application, as I would have hoped. See perhaps How can I get WinForms to stop silently ignoring unhandled exceptions? for this.
Locking the MRE's and moving the WaitAll off the STA thread does the trick.
public partial class AsyncControlCreateTest : Form
{
object locker = new object();
static List<ManualResetEvent> MREs = new List<ManualResetEvent>();
Form loading = new Form() { Text = "Loading...", Width = 100, Height = 100 };
public AsyncControlCreateTest()
{
InitializeComponent();
}
private void AsyncControlCreateTest_Load(object sender, EventArgs e)
{
loading.Show(this);//I want to close when all the async threads have completed
CreateControls();
}
private void CreateControls()
{
int startPoint= 0;
for (int i = 0; i < 100; i++)
{
ManualResetEvent mre = new ManualResetEvent(initialState: false);
UserControl control = new UserControl() { Text = i.ToString() };
control.Load += new EventHandler(control_Load);
Controls.Add(control);
control.Top = startPoint;
startPoint += control.Height;
MREs.Add(mre);
}
Task.Factory.StartNew(new Action(() =>
{
try
{
WaitHandle.WaitAll(MREs.ToArray());
}
catch (Exception ex)
{
MessageBox.Show("error " + ex.Message);
}
finally
{
MessageBox.Show("MRE count = " + MREs.Count);//0 count provides confidence things are working...
loading.Invoke(new Action( () => loading.Close()));
}
}));
}
void control_Load(object sender, EventArgs e)
{
RichTextBox newRichTextBox = new RichTextBox();
UserControl control = sender as UserControl;
control.Controls.Add(newRichTextBox);
Task.Factory.StartNew(new Action(() =>
{
Thread.Sleep(500);
newRichTextBox.Invoke(new Action(() => newRichTextBox.Text = "loaded"));
lock (locker)
{
var ev = MREs.First();
MREs.Remove(ev);
ev.Set();
}
}));
}
}
I have two threads, one thread processes a queue and the other thread adds stuff into the queue.
I want to put the queue processing thread to sleep when its finished processing the queue
I want to have the 2nd thread tell it to wake up when it has added an item to the queue
However these functions call System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code on the Monitor.PulseAll(waiting); call, because I havent synchronized the function with the waiting object. [which I dont want to do, i want to be able to process while adding items to the queue]. How can I achieve this?
Queue<object> items = new Queue<object>();
object waiting = new object();
1st Thread
public void ProcessQueue()
{
while (true)
{
if (items.Count == 0)
Monitor.Wait(waiting);
object real = null;
lock(items) {
object item = items.Dequeue();
real = item;
}
if(real == null)
continue;
.. bla bla bla
}
}
2nd Thread involves
public void AddItem(object o)
{
... bla bla bla
lock(items)
{
items.Enqueue(o);
}
Monitor.PulseAll(waiting);
}
The answer is in the error message you posted:
"Object synchronization method was called from an unsynchronized block of code on the Monitor.PulseAll(waiting);"
You have to call Monitor.PulseAll(waiting) from inside the lock(waiting) block.
Also... you have to call Monitor.Wait from within a lock block as well.
If you have access to .NET 4.0, what you want to do can be achieved by BlockingCollection<T>.
If you want to do it yourself by means of the Monitor class and signaling with Pulse(), you are actually on the right track.
You get the exception because to call Wait(), Pulse() and PulseAll(), you have to own the lock on the specified object. You happen to miss this on waiting.
A sample basic thread-safe queue that can be used:
with foreach on the consumer,
with while or your favorite conditional construct on the producer side,
handles multiple producers/consumers and
uses lock(), Monitor.Pulse(), Monitor.PulseAll() and Monitor.Wait():
.
public class SignaledQueue<T>
{
Queue<T> queue = new Queue<T>();
volatile bool shutDown = false;
public bool Enqueue(T item)
{
if (!shutDown)
{
lock (queue)
{
queue.Enqueue(item);
//Pulse only if there can be waiters.
if (queue.Count == 1)
{
Monitor.PulseAll(queue);
}
}
return true;
}
//Indicate that processing should stop.
return false;
}
public IEnumerable<T> DequeueAll()
{
while (!shutDown)
{
do
{
T item;
lock (queue)
{
//If the queue is empty, wait.
if (queue.Count == 0)
{
if (shutDown) break;
Monitor.Wait(queue);
if (queue.Count == 0) break;
}
item = queue.Dequeue();
}
yield return item;
} while (!shutDown);
}
}
public void SignalShutDown()
{
shutDown = true;
lock (queue)
{
//Signal all waiting consumers with PulseAll().
Monitor.PulseAll(queue);
}
}
}
Sample usage:
class Program
{
static void Main(string[] args)
{
int numProducers = 4, numConsumers = 2;
SignaledQueue<int> queue = new SignaledQueue<int>();
ParameterizedThreadStart produce = delegate(object obj)
{
Random rng = new Random((int)obj);
int num = 0;
while (queue.Enqueue(++num))
{
Thread.Sleep(rng.Next(100));
}
};
ThreadStart consume = delegate
{
foreach (int num in queue.DequeueAll())
{
Console.Write(" {0}", num);
}
};
Random seedRng = new Random();
for (int i = 0; i < numProducers; i++)
{
new Thread(produce).Start(seedRng.Next());
}
for (int i = 0; i < numConsumers; i++)
{
new Thread(consume).Start();
}
Console.ReadKey(true);
queue.SignalShutDown();
}
}
Use Semaphore http://msdn.microsoft.com/library/system.threading.semaphore.aspx it was designed exactly for this
I prefer to use a callback that launches a processing thread that continues until it's caught up, with locks causing simultaneous readers and writers to wait in line:
public delegate void CallbackDelegate();
class Program
{
static void Main(string[] args)
{
Queue<object> items = new Queue<object>();
Processor processor = new Processor(items);
Adder adder = new Adder(items, new CallbackDelegate(processor.CallBack));
Thread addThread = new Thread(new ParameterizedThreadStart(adder.AddItem));
object objectToAdd = new object();
addThread.Start(objectToAdd);
}
}
class Processor
{
Queue<object> items;
public Processor(Queue<object> itemsArg)
{
items = itemsArg;
}
public void ProcessQueue()
{
lock (items)
{
while (items.Count > 0)
{
object real = items.Dequeue();
// process real
}
}
}
public void CallBack()
{
Thread processThread = new Thread(ProcessQueue);
processThread.IsBackground = true;
processThread.Start();
}
}
class Adder
{
Queue<object> items;
CallbackDelegate callback;
public Adder(Queue<object> itemsArg, CallbackDelegate callbackArg)
{
items = itemsArg;
callback = callbackArg;
}
public void AddItem(object o)
{
lock (items) { items.Enqueue(o); }
callback();
}
}