SORU
2 EKİM 2009, Cuma


Süreç Değiştirme.Uygulama etki alanları ile başlayın

Arka plan

Üçüncü taraf çeşitli DLL PDF dosyaları üzerinde çalışmak için kullanan bir Windows hizmeti var. Bu işlem, sistem kaynaklarını biraz kullanabilirsiniz, ve bazen hatalar oluştuğunda, bellek sızıntıları muzdarip gibi görünüyor. DLL diğer yönetilmeyen DLL etrafında sarma yönetilir.

Geçerli Çözüm

Zaten Süreci ile uygulama özel bir konsol uygulaması ve arama içinde DLL için arama sararak bir durumda bu sorunu hafifletmeye çalışıyorum.() Başlatın. İşlem başarısız olur ve bellek sızıntıları ya da yayımlanmamış dosya işlemesi varsa, gerçekten önemli değil. İşlem sona erecek ve OS işler düzelecek.

Bu DLL kullanmak benim app diğer yerler için aynı mantığı uygulamak istiyorum. Ancak, arama İşlemi daha benim çözümü için projeler konsol, ve daha da kazan-plaka kodu yazı ekleme konusunda çok heyecanlı değilim.() Başlangıç ve çıkış uygulamaları konsol ayrıştırır.

Yeni Çözüm

Şık bir alternatif uygulamalar ve Süreç konsol ayrılmış.() Başlangıç uygulama etki alanları, bu gibi görünüyor: http://blogs.geekdojo.net/richard/archive/2003/12/10/428.aspx.

Benim uygulamada benzer bir kodu uygulamaya çalıştım, ama birim testler umut verici olmamıştır. Ayrı bir Uygulama testi dosyası için bir type yaratmak, ama bunu atmayın sakın. Ben o ana etki alanında başka bir FıleStream oluşturmak için girişimi, ve yayımlanmamış dosya kilidi nedeniyle başarısız olur.

İlginç bir şekilde, alt etki alanı için boş DomainUnload olay ekleme ünitesi testi geçmek yapar. Ne olursa olsun, belki de "işçi" uygulama etki alanları sorunumu çözmez. oluşturma endişeleniyorum

Düşünceler?

Kod

/// <summary>
/// Executes a method in a separate AppDomain.  This should serve as a simple replacement
/// of running code in a separate process via a console app.
/// </summary>
public T RunInAppDomain<T>( Func<T> func )
{
    AppDomain domain = AppDomain.CreateDomain ( "Delegate Executor "   func.GetHashCode (), null,
    	new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory } );

    domain.DomainUnload  = ( sender, e ) =>
    {
    	// this empty event handler fixes the unit test, but I don't know why
    };

    try
    {
    	domain.DoCallBack ( new AppDomainDelegateWrapper ( domain, func ).Invoke );

    	return (T)domain.GetData ( "result" );
    }
    finally
    {
    	AppDomain.Unload ( domain );
    }
}

public void RunInAppDomain( Action func )
{
    RunInAppDomain ( () => { func (); return 0; } );
}

/// <summary>
/// Provides a serializable wrapper around a delegate.
/// </summary>
[Serializable]
private class AppDomainDelegateWrapper : MarshalByRefObject
{
    private readonly AppDomain _domain;
    private readonly Delegate _delegate;

    public AppDomainDelegateWrapper( AppDomain domain, Delegate func )
    {
    	_domain = domain;
    	_delegate = func;
    }

    public void Invoke()
    {
    	_domain.SetData ( "result", _delegate.DynamicInvoke () );
    }
}

Birim testi

[Test]
public void RunInAppDomainCleanupCheck()
{
    const string path = @"../../Output/appdomain-hanging-file.txt";

    using( var file = File.CreateText ( path ) )
    {
    	file.WriteLine( "test" );
    }

    // verify that file handles that aren't closed in an AppDomain-wrapped call are cleaned up after the call returns
    Portal.ProcessService.RunInAppDomain ( () =>
    {
    	// open a test file, but don't release it.  The handle should be released when the AppDomain is unloaded
    	new FileStream ( path, FileMode.Open, FileAccess.ReadWrite, FileShare.None );
    } );

    // sleeping for a while doesn't make a difference
    //Thread.Sleep ( 10000 );

    // creating a new FileStream will fail if the DomainUnload event is not bound
    using( var file = new FileStream ( path, FileMode.Open, FileAccess.ReadWrite, FileShare.None ) )
    {
    }
}

CEVAP
2 EKİM 2009, Cuma


Uygulama etki alanları ve etki alanları arası etkileşim çok ince olursa olsun, gerekir emin olun gerçekten anlayan ne kadar az şey işe gitmeden önce bir şeyler yapıyor... Mmm... şey diyelim, "non-standart" :-)

Öncelikle akışı-oluşturma yöntemi aslında "" etki alanı (sürpriz, sürpriz!). varsayılan yürütür Neden? Basit: Uygulama haline geçmesi yöntemi.DoCallBack AppDomainDelegateWrapper bir nesne tanımlanır, ve bu nesnenin varsayılan etki alanı varsa, bu yöntemi infaz ediliyor. MSDN bu hakkında çok az şey demiyor "AppDomainDelegateWrapper.bir kesme noktası ayarlamak için sadece" kolay kontrol etmek için yeterli değil, ama: özellik Çağırmak.

Temelde, sen olmadan bunu yapmak için bir "" nesne. sarıcı yani DoCallBack savı için statik yöntemini kullanın.

Ama nasıl "başka bir etki alanına tartışmanın bu statik yöntem almak ve yürütmek olabilir?" işlev geçer misiniz

En belirgin şekilde Uygulama kullanmaktır.SetData veya rulo kendi, ama ne olursa olsun tam olarak nasıl yapıyorsun, var mı başka bir sorun: eğer "işlev" statik olmayan bir yöntem, nesnenin işte bu tanımlanmış olmalıdır bir şekilde geçirilen bir diğer uygulama. Ya da referans (Uzak tüm güzelliği ile etki alanları arası nesne bir başvuru oluşturma) değeri, alan, alan kopyalanan alır ise () veya geçmiş olabilir. Eski yapmak için sınıf [seri hale getirilebilir] özniteliği ile işaretlenmiş olmalıdır. İkincisi, devralan Adıyla. Eğer sınıf ise de, bunun bir istisnası etki alanı nesnesi geçirmek için girişimi üzerine atılır. Unutma, olsa da, bu geçerek başvuru çok fazla öldürür bütün fikir, çünkü bu yöntem yine de aradı aynı etki alanı nesne var - bu, varsayılan bir.

Sonuç yukarıdaki paragraf, sol iki seçenek: ya bir geçiş yöntemi tanımlanmış bir sınıf ile işaretlenmiş bir [seri hale getirilebilir] özniteliği (ve unutmayın, bu nesne kopyalanan), veya pass statik bir yöntem. , Sizin açınızdan, eski ihtiyacın olacağını düşünüyorum.

Ve bunu her ihtimale karşı kaçmış dikkat etmek istiyorum işaret eden ikinci aşırı RunİnAppDomain (bir o alır Eylem) geçer bir yöntem tanımlanmış bir sınıf değil mi işaretli [seri hale getirilebilir]. Yok herhangi bir sınıf görüyor musun? Gerek yok: anonim temsilciler ilişkili değişkenler içeren, derleyici sizin için bir tane oluşturur. Ve sadece bu yüzden derleyici bunu otomatik sınıf [seri hale getirilebilir] işaretlemek için rahatsız etmez olur. Talihsiz, ama hayat bu :-)

Olması (bir sürü kelime, değil mi?" :- ) ve yeminini statik olmayan ve olmayan[seri hale getirilebilir] yöntem, burada yeni RunİnAppDomain yöntemleri vardır: herhangi geçmek için kuracak

    /// <summary>
    /// Executes a method in a separate AppDomain.  This should serve as a simple replacement
    /// of running code in a separate process via a console app.
    /// </summary>
    public static T RunInAppDomain<T>(Func<T> func)
    {
        AppDomain domain = AppDomain.CreateDomain("Delegate Executor "   func.GetHashCode(), null,
            new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory });

        try
        {
            domain.SetData("toInvoke", func);
            domain.DoCallBack(() => 
            { 
                var f = AppDomain.CurrentDomain.GetData("toInvoke") as Func<T>;
                AppDomain.CurrentDomain.SetData("result", f());
            });

            return (T)domain.GetData("result");
        }
        finally
        {
            AppDomain.Unload(domain);
        }
    }

    [Serializable]
    private class ActionDelegateWrapper
    {
        public Action Func;
        public int Invoke()
        {
            Func();
            return 0;
        }
    }

    public static void RunInAppDomain(Action func)
    {
        RunInAppDomain<int>( new ActionDelegateWrapper { Func = func }.Invoke );
    }

Eğer hala benimleysen, takdir ediyorum :-)

Şimdi, bu mekanizmayı tamir çok fazla zaman geçirdikten sonra, zaten amaçsız olduğunu sana söyleyeceğim.

Şey, uygulama etki alanları amaçlarınız için size yardım etmeyecek. Onlar yalnızca yönetilmeyen kod sızıntısı ve istediği kadar kalabilir iken yönetilen nesneleri ilgilen. Yönetilmeyen kod bile uygulama etki alanları gibi şeyler var bilmiyor. Sadece işlemler hakkında bilir.

Böylece, sonunda, en iyi seçenek, geçerli bir çözüm kalır: sadece başka bir işlem spawn ve mutlu olabilirsiniz. Ve bir önceki cevap ile aynı fikirdeyim, başka bir uygulama her durum için konsol yazmak zorunda değilsin. Sadece statik bir yöntem tam adını iletebilir ve konsol uygulaması yükü var, derleme, türü yük ve yöntemini çağırır. Aslında çok aynı şekilde uygulama etki alanları ile çalıştın olarak çok iyi tasarlanmış bir paket. Sen-ebilmek yaratmak bir yöntem denen bir şey gibi "RunİnAnotherProcess", hangi olacak incelemek argüman, tam tür adı ve Yöntem adı olacak (olsa iyi bir yöntemdir statik) ve spawn konsol uygulaması olacak mı gerisi.

Kendine iyi bak, iyi şanslar.

  • Fyodor

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • calicoJake

    calicoJake

    29 EKİM 2007
  • FRED

    FRED

    1 EKİM 2005
  • Within Temptation

    Within Tempt

    18 EYLÜL 2006