Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slim synchronization classes are per AppDomain or per Process?

All articles in Internet says that using Thread.Abort is evil (because synchronization primitives belongs to operating system, and process doesn't terminate yet, and primitives might remain locked after thread aborting). Developers advises to terminate whole processes instead, because operation system will free synchronization primitives when process stops.

  1. Will AppDomain unloading help, If one will use Slim synchronization primitives? (With .net 4.0 several new classes have been added relating to threading: ManualResetEventSlim, SemaphoreSlim, ReaderWriterLockSlim).

    Documentation says that these primitives can't be used beween different processes, because implementation code of primitives is fully managed. But I don't understand - will these primitives work through AppDomain border. (see Can't set synchronization context when using appdomains)

  2. If yes, how they do that? If no, then why documentation omit this limitation?

UPD: All my code is trusted by me, including the code inside the domain which i unload. I don't want to leave the thread working, when the time comes to terminate it. I want to terminate (abort) thread instead of "setting flag" and "making nice architecture". If it is neccessary to create additional thread first (i think this is necessary at start of background processing in separate domain to create one more thread), i will do. I don't want to use "setting flag" approach, because it requires me to instrument background algorithm with flag checks, i shouldn't, it's the runtime or compiler should automate that instrumentation for me. Right now there is no such instrumentation, that is why I am trying to apply the approach with domain unloading.

Adding checks between each instruction (or in deep nested cycles) will slow the code significantly. Adding check in random locations will not give guaranties of prompt termination. If difficulties of writing abort-safe code can be solved, why not to try to abort threads and unload domain?

like image 676
R2D4 Avatar asked Jun 01 '15 15:06

R2D4


1 Answers

You misunderstands the AppDomain, Process and Thread definitions - AppDomains always lives in one process, but one process can be a master for different AppDomains *:

The ability to run multiple applications within a single process dramatically increases server scalability.

  • this is similar for the Thread, just for mention.

So, the answer for your question is Yes, the slim synchronization primitives will work with various AppDomains, as there are no cross-process calls in such architecture, only a logical distinction for various processes.

As for the linked question, there are no problem with synchronization primitives there, only with SynchronizationContext, which is Thread-specific, but not AppDomain-specific.

You can find a great answer about the difference between AppDomain, Thread and Process here: Difference between AppDomain, Assembly, Process, and a Thread

As for the unloading the AppDomain, I think that you can refactor your code as you can start a worker Thread into your AppDomain with limited access to the system resources, and simply wait for it to be finished, something like it mentioned here:

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        var ad = AppDomain.CreateDomain("WhereTheWorkHappens");

        Task<string> t = DoWorkInOtherDomain(ad);
        Console.WriteLine("waiting...");
        Console.WriteLine(t.Result);

        Console.ReadLine();
    }

    static Task<string> DoWorkInOtherDomain(AppDomain ad)
    {
        var ch = new MarshaledResultSetter<string>();

        Worker worker = (Worker)ad.CreateInstanceAndUnwrap(typeof(Worker).Assembly.FullName, typeof(Worker).FullName);
        worker.DoWork(ch);

        return ch.Task;
    }

    class Worker : MarshalByRefObject
    {
        public void DoWork(MarshaledResultSetter<string> callback)
        {
            ThreadPool.QueueUserWorkItem(delegate
            {
                Thread.SpinWait(500000000);
                callback.SetResult(AppDomain.CurrentDomain.FriendlyName);
            });
        }
    }

    class MarshaledResultSetter<T> : MarshalByRefObject
    {
        private TaskCompletionSource<T> m_tcs = new TaskCompletionSource<T>();
        public void SetResult(T result) { m_tcs.SetResult(result); }
        public Task<T> Task { get { return m_tcs.Task; } }
    }
}

As an additional idea for you, you can read about Sandboxing your code with TPL, which, as I think, is better approach as you don't manually manage the system resources and has less chances for being hacked by your non-trusted code.

Also, you can find a GitHub project with Cross-AppDomain Marshaling friendly TPL wrappers for APM

like image 149
VMAtm Avatar answered Sep 27 '22 21:09

VMAtm