Why this code which runs on seperate AppDomain Crashes my process? - c#

I'm trying to figure out how to use AppDomains.
The Need:
I have a single process web application which dynamically loads dlls and invokes it using reflection.
I want to ensure that a crash in a loaded dll does not crash the process, in addition to creating a seperation between "external" code and my base code.
So I have this "isloated" class:
public sealed class Isolated<T> : IDisposable where T : MarshalByRefObject
{
private AppDomain _domain;
private T _value;
public Isolated()
{
_domain = AppDomain.CreateDomain("Isolated:" + Guid.NewGuid(),
null, AppDomain.CurrentDomain.SetupInformation);
Type type = typeof(T);
_value = (T)_domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
}
public T Value
{
get
{
return _value;
}
}
public void Dispose()
{
if (_domain != null)
{
AppDomain.Unload(_domain);
_domain = null;
}
}
}
and I wrote this code below, my expectation is it would not crush the process, but it does.
public class Work : MarshalByRefObject
{
public void DoSomething()
{
Thread thread = new Thread(new ThreadStart(() =>
{
throw new Exception();
}));
thread.IsBackground = true;
thread.Start();
while (true)
{
System.Diagnostics.Trace.WriteLine("Hello from main thread");
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
using (Isolated<Work> isolated = new Isolated<Work>())
{
isolated.Value.DoSomething();
}
}
Can you please help me understand what I'm doing wrong?

There is no way to prevent the process termination.
As suggested by #Jehof,
More info here: http://www.codeproject.com/Articles/635497/AppDomains-Wont-Protect-Host-From-a-Failing-Plugin

Related

How to detect if method is called from critical section or outside it for c#?

Preconditions:
I have to fix synchonization issues in very big legacy spaghetty codebase. There are some classes that must be synchronized. But there are lots of usages for these classes. It is why I am looking for way to catch issues with debug guards.
There is one of ideas to report problem in usage of some classes.
Class for debug purposes:
public class AsyncChecker {
private readonly Thread myThread;
private volatile bool myTurnedOn;
public AsyncChecker() {
myThread = Thread.CurrentThread;
myTurnedOn = false;
}
public void turnOn() {
myTurnedOn = true;
}
public void checkThread() {
if ( myTurnedOn && Thread.CurrentThread != myThread ) {
Debug.LogError( "illegal thread" );
}
}
public void checkMultiThreadSafety() {
if ( myTurnedOn ) {
//there is code that can determine if method called from critical
//section or not even if we call from the same thread
//Monitor.IsEntered( ) works only if there is call from another thread
}
}
}
Some legacy class that can or cannot be accessed in concurrency:
public class SomeLogic {
private readonly AsyncChecker myAsyncChecker = new AsyncChecker();
public void logicOne() {
myAsyncChecker.checkMultiThreadSafety();
//some logic A
}
public void logicTwo() {
myAsyncChecker.checkMultiThreadSafety();
//some logic B
}
}
There is purpose:
public void someMethodInDeepLegacyCode() {
lock (someLock) {
someLogicClassInstance.logicOne();
}
}
public void anotherSomeMethodInDeepLegacyCode() {
someLogicClassInstance.logicTwo(); //there is access without synchronization,
//would like to have exception, or assertion, or error log or something else
}
Monitor.IsEntered can be used only partially. Only if we called from different thread but not for the same.

Idle event not executing after registration and show?

I have an application where I would like to execute certain orders on a certain thread when that thread is idling. So I created a manager to handle this for me, launched of a form.show and created a thread manager:
public class ThreadManager
{
static List<ThreadAble> orders = new List<ThreadAble>();
public static bool running = false;
public static void execute(ThreadAble action)
{
orders.Add(action);
}
public static void RegisterAPIThreadAndHold()
{
running = true;
Application.Idle += Application_Idle;
}
private static void Application_Idle(object sender, EventArgs e)
{
if (orders.Count != 0)
{
ThreadAble f = orders.First();
orders.Remove(f);
f.execute();
}
}
}
public interface ThreadAble {
void execute();
}
public static class formstuff{
private static void ShowDialogThreaded(){
form.Show(owner);
ThreadManager.RegisterAPIThreadAndHold();
}
}
}
I then try to use this using it by:
public class TestRegister : ThreadAble
{
public void execute()
{
throw new NotImplementedException();
}
}
ThreadManager.execute(new TestRegister());
Now this should throw an exception, however it doesn't. I have also tried with more complicated behaviour and breakpoints but this code seems to never get executed. Am I misunderstanding how the Application_Idle works? Is there another way to make it so that this thread starts executing my code (has to be this thread) when it's done with handling the GUI code and not doing anything else (it might be required to do other things a well).
I already veritfied that RegisterAPIThreadAndHold() is executed.

Joining a thread started with StartNew()

When using the StartNew() method to kick off a process on a new thread, I need to figure out how to make another call into this object in that same thread (I assume this would be some sort of Join operation?).
The following example is dumbed down to illustrate the meat of what I am trying to do. I am well aware it is severely lacking in basic concurrency considerations. But I didn't want to cloud the code with all of that logic, so please forgive me on that.
The following console app shows what I am trying to accomplish. Assume on the StartNew() call a new thread with ID 9976 is created and the method invoked there. I would like the subsequent call to ProcessImmediate() in the file system watcher change event handler to be made on thread 9976 as well. As it stands, the call would share the same thread that is used for the file system watcher change event.
Can this be done, and if so, how?
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
public void Run()
{
_activity = new Activity();
// start activity on a new thread
Task.Factory.StartNew(() => _activity.Go());
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "c:\temp";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity
{
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
System.Threading.Thread.Sleep(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
DoSomethingInteresting();
}
public bool Stop { get; set; }
}
}
* UPDATE *
Thanks for the excellent responses. I took Mike's suggestion and implemented it for my console app. Below is the full working code which also includes the use of a cancellation token. I post this in case someone else might find it useful.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
runner.Stop();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
private CancellationTokenSource _cts = new CancellationTokenSource();
public void Stop() { _cts.Cancel(); }
public void Run()
{
_activity = new Activity();
// start activity on a new thread
var task = new Task(() => _activity.Go(_cts.Token), _cts.Token, TaskCreationOptions.LongRunning);
task.Start();
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "C:\\Temp\\FileSystemWatcherPath";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go(CancellationToken ct)
{
Thread.CurrentThread.Name = "Go";
while (!ct.IsCancellationRequested)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(5000);
}
Console.WriteLine("Exiting");
}
protected virtual void DoSomethingInteresting()
{
Console.WriteLine(string.Format("Doing Something Interesting on thread {0}", Thread.CurrentThread.ManagedThreadId));
}
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
_processing.Set();
}
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
}
First, you should use TaskCreationOptions.LongRunning if you are creating a task that will not complete quickly. Second, use an AutoResetEvent to signal the waiting thread to wake up. Note that below ProcessImmediate will return before DoSomethingInteresting has completed running on the other thread. Example:
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
User mike has given a better solution, which will be appropriate when you like to call the same method immediately. If you want to call a different methods immediately I'll expand mike's answer to achieve that.
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
private ConcurrentQueue<Action> actionsToProcess = new ConcurrentQueue<Action>();
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
while(!actionsToProcess.IsEmpty)
{
Action action;
if(actionsToProcess.TryDeque(out action))
action();
}
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate(Action action)
{
actionsToProcess.Enqueue(action);
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
To execute different methods on the same thread you can use a message loop that dispatches incoming requests. A simple option would be to use the event loop scheduler of the Reactive Extensions and to "recursively" schedule your Go() function - if in the mean time a different operation is scheduled it would be processed before the next Go() operation.
Here is a sample:
class Loop
: IDisposable
{
IScheduler scheduler = new EventLoopScheduler();
MultipleAssignmentDisposable stopper = new MultipleAssignmentDisposable();
public Loop()
{
Next();
}
void Next()
{
if (!stopper.IsDisposed)
stopper.Disposable = scheduler.Schedule(Handler);
}
void Handler()
{
Thread.Sleep(1000);
Console.WriteLine("Handler: {0}", Thread.CurrentThread.ManagedThreadId);
Next();
}
public void Notify()
{
scheduler.Schedule(() =>
{
Console.WriteLine("Notify: {0}", Thread.CurrentThread.ManagedThreadId);
});
}
public void Dispose()
{
stopper.Dispose();
}
}
static void Main(string[] args)
{
using (var l = new Loop())
{
Console.WriteLine("Press 'q' to quit.");
while (Console.ReadKey().Key != ConsoleKey.Q)
l.Notify();
}
}

Return feedback from an event which is being waited on

In it's simplicity what I am trying to do is handle "Doing Something" by firing off a process on a seperate thread to do what I need to do and waiting for an event to be raised to say "I have finished doing what I need to do". In the EventArgs though I will have a property for any errors which may be encountered during the process. Here is a simplified example of my situation.
public class MessageHandler
{
private AutoResetEvent MessageHasSent = new AutoResetEvent(false);
public void SendMessage()
{
MessageSender ms = new MessageSender();
ms.MessageSent += new EventHandler<MessageSentEventArgs>(MessageHandler_MessageSent);
Thread t = new Thread(ms.Send());
t.Start();
MessageHasSent.WaitOne();
//Do some check here
//Same again but for "Message recieved"
}
void MessageHandler_MessageSent(object sender, MessageSentEventArgs e)
{
if (e.Errors.Count != 0)
{
//What can I do here to return to the next step after waitone?
}
else
MessageHasSent.Set();
}
}
public class MessageSender
{
public event EventHandler<MessageSentEventArgs> MessageSent;
public void Send()
{
//Do some method which could potentiallialy return a List<Error>
MessageSent(this, new MessageSentEventArgs() { Errors = new List<Error>() });
}
}
public class Error { }
public class MessageSentEventArgs : EventArgs
{
public List<Error> Errors;
}
Essentially once the event has been raised from Send the code will continute, however I want some way of the event giving feedback, potentially using the MessageHasSent. I have tried different methods, I thought if I called Close instead of Set it would perhaps allow me to access something such as IsClosed. You could throw an exception or set a flag outside of the scope of the event to check but I feel like this is dirty.
Any suggestions?
Using the TPL isn't applicable in my case as I am using .NET 3.5.
Since it seems that this entire section of code is already running in a background thread, and you're doing nothing more than starting up a new thread just so that you can wait for it to finish, you'd be better off just calling Send directly, rather than asynchronously.
You don't need to fire off an event when you're completed.
You don't need to signal the main thread when it needs to continue.
You don't need to log the exceptions in a List, you can just throw them and catch them in SendMessage with a try/catch block.
This will do what you want:
public class MessageHandler
{
private AutoResetEvent MessageHasSent = new AutoResetEvent(false);
private bool IsSuccess = false;
public void SendMessage()
{
MessageSender ms = new MessageSender();
ms.MessageSent += new EventHandler<MessageSentEventArgs>(MessageHandler_MessageSent);
Thread t = new Thread(ms.Send());
t.Start();
MessageHasSent.WaitOne();
if(IsSuccess)
//wohooo
else
//oh crap
//Same again but for "Message recieved"
}
void MessageHandler_MessageSent(object sender, MessageSentEventArgs e)
{
IsSuccess = e.Errors.Count == 0;
MessageHasSent.Set();
}
}
public class MessageSender
{
public event EventHandler<MessageSentEventArgs> MessageSent;
public void Send()
{
//Do some method which could potentiallialy return a List<Error>
MessageSent(this, new MessageSentEventArgs() { Errors = new List<Error>() });
}
}
public class Error { }
public class MessageSentEventArgs : EventArgs
{
public List<Error> Errors;
}

threads synchronisation in little application

I have the following problem. I finishing my application, which one do something. Simultaneously some code (drwaing charts and save data to log file) can be using by a few threads. I can't synchornize save data which those threads. There is some exception that file is using by other process. On form1.cs file I'm starting this threads, which are starting function on another file (charts.cs).
Part of form1.cs file:
UserControl1 us = ctrl as UserControl1;
us.newThread = new Thread(new ThreadStart(us.wykres.CreateChart));
us.newThread.Start();
charts.cs file:
public class Charts
{
private StreamWriter sw = new StreamWriter("logFile.txt", true);
static readonly object LogLock = new object();
private ZedGraphControl zzz;
public ZedGraphControl ZZZ
{
get { return zzz; }
set { zzz = value; }
}
private UserControl1 uc1;
public UserControl1 Uc1
{
get { return uc1; }
set { uc1 = value; }
}
//jakiś kod
void WriteLog(string wpis, StreamWriter streamW)
{
lock (LogLock)
{
streamW.WriteLine(wpis);
streamW.Flush();
}
}
public void CreateChart()
{
try
{
//tutaj znów jakiś kod
//poniżej najważniejsza
while ()
{
if ()
{
if (go == false)
{
ZZZ.Invoke(Uc1.warnDelegate, "Osiągnięto strefę bezpiecznych wartości");
}
wpis = "jakis string";
WriteLog(wpis, sw);
wpis = null;
}
if ()
{
if ()
{
ZZZ.Invoke(Uc1.warnDelegate, "Osiągnięto strefę 1");
}
wpis = "jakis string";
WriteLog(wpis, sw);
wpis = null;
}
else if ()
{
if ()
{
ZZZ.Invoke(Uc1.warnDelegate, "Osiągnięto strefę 2");
}
wpis = "jakis string";
WriteLog(wpis, sw);
wpis = null;
}
//jakiś kod odnośnie rysowania wykresow
ZZZ.Invoke(Uc1.myDelegate);
Thread.Sleep(odstepCzasu * 1000);
}
}
catch (InvalidOperationException e)
{
MessageBox.Show(e.Message);
}
catch (ThreadAbortException)
{
}
}
}
}
Part of userControl1.cs file:
public delegate void RefreshDelegate();
public delegate void ShowWarningDialogDelegate(string aaa, string bbb, string ccc);
public RefreshDelegate myDelegate;
public ShowWarningDialogDelegate warnDelegate;
public Thread newThread = null;
public Charts wykres = null;
public UserControl1()
{
InitializeComponent();
wykres = new Charts();
wykres.ZZZ = zedGraphControl1;
wykres.Uc1 = this;
myDelegate = new RefreshDelegate(wykres.ZZZ.Refresh);
warnDelegate = new ShowWarningDialogDelegate(minDelegate);
}
private void minDelegate(string strLabel1, string strLabel2)
{
WarningForm forma = new WarningForm(strLabel1, strLabel2);
forma.Show();
}
Can you show me how to synchronize it to happen that a few threads have accessed in the same time to a log file (when they want to save something)? I heard that this is typical producer-consumer problem but I d'nt know how to use it in my case. I will be very greatefull for any halp. Regards.
You can use the lock() function of C# to lock an object which will allow you to only allow one thread at a time inside the lock() function.
1) Create an object to use as a lock in your class.
static readonly object LogLock = new object();
2) Move your logging code into it's own method and use the lock() function to force only one thread at a time to execute the critical area, in this case the StreamWriter stuff.
void WriteLog(string wpis, StreamWriter sw)
{
lock (LogLock)
{
sw.WriteLine(wpis);
sw.Flush();
}
}
3) Call your threadsafe logging method concurrently with as many threads as you want.
WriteLog("test log text.", sw);
take a look at the Semaphore class. You can use it to synchronize threads accessing the file. In short, you want to have only one thread write to the file at any given point in time.
You can create additional method for writing log.
Then you can synchronize this method.

Categories