2011-10-25 12 views
12

मैं एक प्लगइन सिस्टम लिखने की कोशिश कर रहा हूं जो प्रबंधित प्लगइन लोड कर सकता है। यदि कोई अपवाद हैं तो मेजबान प्लगइन को अनलोड करने में सक्षम होना चाहिए। मेरी POC के लिए मैं सी # है कि इस तरह एक अपवाद फेंकता में एक नमूना कोड पुस्तकालय है ...होस्टिंग क्लियर और थ्रेडिंग अपवाद

public static int StartUp(string arguments) 
{ 
     Console.WriteLine("Started exception thrower with args {0}", arguments); 
     Thread workerThread = new Thread(() => 
      { 
       Console.WriteLine("Starting a thread, doing some important work"); 
       Thread.Sleep(1000); 
       throw new ApplicationException(); 
      } 
     ); 
     workerThread.Start(); 
     workerThread.Join(); 
     Console.WriteLine("this should never print"); 
     return 11; 
    } 

तो मैं इस तरह देशी Win32 कंसोल अनुप्रयोग है ..

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ICLRMetaHost *pMetaHost  = NULL; 
    HRESULT hr; 
    ICLRRuntimeInfo *runtimeInfo = NULL;  
    __try 
    { 
     hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); 
     hr = pMetaHost->GetRuntime(L"v4.0.30319",IID_ICLRRuntimeInfo,(LPVOID*)&runtimeInfo); 
     ICLRRuntimeHost *runtimeHost = NULL; 
     hr = runtimeInfo->GetInterface(CLSID_CLRRuntimeHost,IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost);  
     ICLRControl* clrControl = NULL; 
     hr = runtimeHost->GetCLRControl(&clrControl); 
     ICLRPolicyManager *clrPolicyManager = NULL; 
     clrControl->GetCLRManager(IID_ICLRPolicyManager, (LPVOID*)&clrPolicyManager); 
     clrPolicyManager->SetDefaultAction(OPR_ThreadAbort,eUnloadAppDomain); 
     hr = runtimeHost->Start(); 
     DWORD returnVal = NULL;   
     hr = runtimeHost->ExecuteInDefaultAppDomain(L"ExceptionThrower.dll",L"ExceptionThrower.MainExceptionThrower",L"StartUp",L"test",&returnVal);   
     runtimeHost->Release(); 
    } 
    __except(1) 
    { 
     wprintf(L"\n Error thrown %d",e); 
    } 
    return 0; 
} 

मुद्दा यह है कि अगर है मैं उपर्युक्त कोड का उपयोग करता हूं, होस्ट प्रबंधित कोड चलाएगा (लाइन "इसे प्रिंट नहीं करना चाहिए" प्रिंटिंग समाप्त हो जाएगा) अगर मैं clrPolicyManager-> SetUnhandledExceptionPolicy (eHostDeterminedPolicy) को हटा देता हूं, तो होस्ट प्रक्रिया क्रैश हो जाएगी।

अप्रबंधित होस्ट में कुछ भी किया जा सकता है कि यह गलती से ऐप को रनटाइम से हटा सकता है और काम करना जारी रख सकता है?

+0

आपका कोड .NET 1.x अपवाद हैंडलिंग नीति सक्षम करता है। जो सिर्फ धागे को समाप्त करता है। आप जो चाहते हैं उसे नहीं, आपको आईसीएलआर पॉलिसी मैनेजर :: SetDefaultAction() को थ्रेड एबॉर्ट पर ऐप डोमेन को अनलोड करने के लिए कहने के लिए भी कॉल करना होगा। आपके पास अभी भी एक मृत धागा है, अपवाद को पकड़ने के लिए __try/__ पकड़ का उपयोग करें। –

+0

मैंने निम्नलिखित पंक्ति clrPolicyManager-> SetDefaultAction (OPR_ThreadAbort, eUnloadAppDomain) जोड़ा; कोड में, मैंने कोड अपडेट किया है, लेकिन प्रभाव समान है, मेजबान प्रक्रिया अभी भी –

+0

क्रैश हो गई है, आपने टिप्पणी के "मृत धागे" भाग को याद किया होगा। आपको एसईएच अपवाद पकड़ना होगा। अपवाद कोड 0xe0434f4d है। http://msdn.microsoft.com/en-us/library/s58ftw19%28v=VS.100%29.aspx –

उत्तर

1

आप प्रत्येक दी प्लगइन के लिए विशेष रूप से एक नया AppDomain शुरू करने और इसके अंदर शुरू कर सकते हैं। http://msdn.microsoft.com/en-us/library/ms164323.aspx

प्रत्येक ऐपडोमेन एक अलग वातावरण है जहां कोड निष्पादित हो सकता है। एक ऐपडोमेन में होने वाली अपवादों को बाकी हिस्सों से अलग किया जा सकता है। देखें: http://msdn.microsoft.com/en-us/library/system.appdomain(v=VS.100).aspx

+0

डोमेन मेमोरी/सुरक्षा सैंडबॉक्स प्रदान करते हैं, लेकिन वे थ्रेड अलगाव प्रदान नहीं करते हैं, जो थ्रेड सीएलआर स्तर पर बनाए जाते हैं, और वे किसी भी डोमेन में निष्पादित कर सकते हैं, इसलिए अगर थ्रेड पर एक अनचाहे अपवाद होता है, तो संपूर्ण सीएलआर दुर्घटनाग्रस्त हो जाता है .. –

+0

@ एनपी-हार्ड - एमएसडीएन देखें: "एप्लिकेशन को डोमेन को उन कार्यों को अलग करने के लिए उपयोग करें जो प्रक्रिया को कम कर सकते हैं। यदि किसी कार्य को निष्पादित करने वाले ऐपडोमेन की स्थिति अस्थिर हो जाती है, तो प्रक्रिया को प्रभावित किए बिना ऐपडोमेन को अनलोड किया जा सकता है। यह महत्वपूर्ण है जब किसी प्रक्रिया को पुनरारंभ किए बिना लंबी अवधि के लिए चलाना चाहिए। आप उन कार्यों को अलग करने के लिए एप्लिकेशन डोमेन का भी उपयोग कर सकते हैं जिन्हें डेटा साझा नहीं करना चाहिए। " (http://msdn.microsoft.com/en-us/library/system.appdomain.aspx) – Polity

+0

@ एनपी-हार्ड - कृपया पढ़ें: http://ikickandibite.blogspot.com/2010/04/appdomains-and- true-isolation.html जो आपकी समस्या से बिल्कुल संबंधित है। मुझे यकीन नहीं है कि क्या हम सीएलआर-होस्टिंग एपीआई का उपयोग करके इसे दोहरा सकते हैं। यदि नहीं, तो आप प्लगइन-डीएल के लिए एक प्रबंधित बूटस्ट्रैपर विकसित कर सकते हैं जो एक अनचाहे अपवाद – Polity

1

SetDefaultAction के साथ एक साथ निम्न क्रैश निराकरण जोड़ने की तरह लग रहा:

clrPolicyManager->SetUnhandledExceptionPolicy(EClrUnhandledException::eHostDeterminedPolicy); 
+0

जैसा कि प्रश्न में उल्लिखित है "समस्या यह है कि यदि मैं उपर्युक्त कोड का उपयोग करता हूं, तो होस्ट चालू हो जाएगा प्रबंधित कोड (लाइन "इसे प्रिंट नहीं करना चाहिए" प्रिंटिंग समाप्त हो जाएगा) अगर मैं clrPolicyManager-> SetUnhandledExceptionPolicy (eHostDeterminedPolicy) को हटा देता हूं, तो होस्ट प्रक्रिया क्रैश हो जाएगी। " –

0

आपने एक बहुत ही रोचक सवाल उठाया, इसके लिए धन्यवाद।

मुझे लगता है इस लेख काफी मददगार साबित होंगे: http://etutorials.org/Programming/programming+microsoft+visual+c+sharp+2005/Part+III+More+C+Language/Chapter+9+Exception+Handling/Unhandled+Exceptions/

+3

नग्न लिंक अच्छे उत्तरों के लिए नहीं बनाते हैं। कृपया ** यहां ** लेख सारांशित कर सकते हैं। यदि लिंक की गई सामग्री कभी भी चलती है तो यह जवाब बेकार से भी बदतर हो जाता है। इसके अलावा आपके सभी उत्तरों पर हस्ताक्षर करने की कोई आवश्यकता नहीं है, उनके पास आपकी फ्लेयर संलग्न है जो आपका हस्ताक्षर है। – ChrisF

3

सबसे पहले, यदि आप ऊपर कोड के साथ आवेदन दुर्घटना को रोकने के लिए चाहते हैं, तो आप SetUnhandledExceptionFilter उपयोग करने के लिए, इस तरह की आवश्यकता होगी:

LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionInfo) 
{ 
    // do something useful 
    return EXCEPTION_EXECUTE_HANDLER; // prevent crash 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); 
     ... 
} 

लेकिन यह वास्तव में आप जो चाहते हैं वह नहीं हो सकता है। एक समाधान (जैसा कि पोलिटी I द्वारा प्रस्तावित किया गया है) एक मध्यस्थ ऐपडोमेन बनाना है जो आसानी से सभी अनचाहे अपवादों को पकड़ सकता है। आप क्या कर सकते हैं कि सी # में, इस तरह:

public class PluginVerifier 
{ 
    public static int CheckPlugin(string arguments) 
    { 
     AppDomain appDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString()); 
     appDomain.UnhandledException += AppDomainUnhandledException; 
     object obj = appDomain.CreateInstanceAndUnwrap("ExceptionThrower", "ExceptionThrower.MainExceptionThrower"); 
     object ret = obj.GetType().InvokeMember("Startup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, obj, new object[] { arguments }); 
     AppDomain.Unload(appDomain); 
     return (int)ret; 
    } 

    private static void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     AppDomain appDomain = (AppDomain)sender; 
     // the following will prevent "this should never print" to happen 
     AppDomain.Unload(appDomain); 
    } 
} 

इस तथापि काम करने में सक्षम होने के लिए, यदि आप अपने प्लगइन वर्गों के लिए दो परिवर्तन करने की जरूरत है:

  • वे MarshalByRefObject
  • से निकाले जाते हैं चाहिए
  • प्लगइन विधि स्थिर नहीं होना चाहिए (स्थिर तरीकों फोन AppDomain फिल्टर के माध्यम से मत जाओ)

तो अपने वर्ग इस तरह लिखा जाएगा:

+०१२३५१६४१०६
public class MainExceptionThrower: MarshalByRefObject 
{ 
    public int StartUp(string arguments) 
    { 
    ... 
    } 
} 

आप ऐसा करते हैं, तो आप SetUnhandledExceptionPolicy, SetActionOnFailure, या SetDefaultAction के लिए कॉल निकाल सकते हैं और सिर्फ इस तरह बूटस्ट्रैप कोड की जगह: आप ऊपर अपने स्टार्टअप कोड के साथ इस प्रयास करें

hr = runtimeHost->ExecuteInDefaultAppDomain(L"PluginSystem.dll", L"PluginSystem.PluginVerifier", L"CheckPlugin", L"test", &returnVal);   

, यह कॉल एचआर = 0x80131604 लौटाएगी, जो कि COR_E_TARGETINVOCATION (TargetInvocationException) है।

संबंधित मुद्दे