2008-10-08 11 views
7

मेरे पास कुछ सिस्टम है। डायग्नोटिक्स। प्रोसेस चलाने के लिए। मैं स्वचालित रूप से उन पर बंद विधि को कॉल करना चाहता हूं। स्पष्ट रूप से "उपयोग" कीवर्ड मेरे लिए यह करता है।मैं प्रोग्रामिंग रूप से सी # में "उपयोग" कीवर्ड का उपयोग कैसे करूं?

क्या यह उपयोग करने वाले कीवर्ड का उपयोग करने का तरीका है?

foreach(string command in S) // command is something like "c:\a.exe" 
{ 
    try 
    { 
     using(p = Process.Start(command)) 
     { 
      // I literally put nothing in here. 
     } 
    } 
    catch (Exception e) 
    { 
     // notify of process failure 
    } 
} 

मैं समसामयिक रूप से चलाने के लिए कई प्रक्रियाएं शुरू करना चाहता हूं।

उत्तर

15
using(p = Process.Start(command)) 

यह संकलन के रूप में Process वर्ग IDisposable लागू करता है, फिर भी आप वास्तव में Close विधि कॉल करना चाहते हैं।
तर्क यह होगा कि Dispose विधि आपके लिए Close पर कॉल करेगी, और परावर्तक का उपयोग करके सीएलआर में खुदाई करके, हम देख सकते हैं कि यह वास्तव में हमारे लिए ऐसा करता है। अब तक सब ठीक है।

फिर परावर्तक का उपयोग करके, मैंने देखा कि Close विधि क्या करती है - यह अंतर्निहित देशी Win32 प्रक्रिया संभालती है, और कुछ सदस्य चर को साफ़ करती है। यह (बाहरी संसाधनों को जारी करना) बिल्कुल आईडीस्पोज़ेबल पैटर्न क्या करना चाहिए।

हालांकि मुझे यकीन नहीं है कि यह वही है जो आप यहां प्राप्त करना चाहते हैं।

अंतर्निहित हैंडल को जारी करना बस विंडोज़ को कहता है 'अब मुझे इस अन्य प्रक्रिया को ट्रैक करने में दिलचस्पी नहीं है'। किसी भी समय यह वास्तव में अन्य प्रक्रिया को छोड़ने का कारण नहीं बनता है, या आपकी प्रक्रिया का इंतजार कर सकता है।

यदि आप उन्हें छोड़ना चाहते हैं, तो आपको प्रक्रियाओं पर p.Kill() विधि का उपयोग करने की आवश्यकता होगी - हालांकि सलाह दी जानी चाहिए कि प्रक्रियाओं को मारना कभी भी अच्छा विचार नहीं है क्योंकि वे स्वयं के बाद साफ नहीं हो सकते हैं, और छोड़ सकते हैं भ्रष्ट फाइलों के पीछे, और इसी तरह।

यदि आप उनके लिए बाहर निकलने के लिए प्रतीक्षा करना चाहते हैं, तो आप p.WaitForExit() का उपयोग कर सकते हैं - हालांकि यह केवल तभी काम करेगा यदि आप एक समय में एक प्रक्रिया की प्रतीक्षा कर रहे हैं। यदि आप सभी के साथ एक साथ इंतजार करना चाहते हैं, तो यह मुश्किल हो जाता है।

आम तौर पर आप इस के लिए WaitHandle.WaitAll का उपयोग करते हैं, लेकिन वहाँ के रूप में एक System.Diagnostics.Process के बाहर एक WaitHandle वस्तु प्राप्त करने के लिए कोई रास्ता नहीं है, तो आप ऐसा नहीं कर सकते यह (गंभीरता से, WTF माइक्रोसॉफ्ट सोच रहे थे?)।

आप प्रत्येक प्रक्रिया के लिए एक थ्रेड स्पिन कर सकते हैं, और उन धागे में 'WaitForExit' को कॉल कर सकते हैं, लेकिन यह भी करने का गलत तरीका है।

आपको मूल Win32 WaitForMultipleObjects फ़ंक्शन तक पहुंचने के लिए पी/इनवॉक का उपयोग करना होगा।

यहां एक नमूना है (जो मैं परीक्षण किया है, और वास्तव में काम करता है)

[System.Runtime.InteropServices.DllImport("kernel32.dll")] 
static extern uint WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds); 

static void Main(string[] args) 
{ 
    var procs = new Process[] { 
     Process.Start(@"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 2'"), 
     Process.Start(@"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 3'"), 
     Process.Start(@"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 4'") }; 
    // all started asynchronously in the background 

    var handles = procs.Select(p => p.Handle).ToArray(); 
    WaitForMultipleObjects((uint)handles.Length, handles, true, uint.MaxValue); // uint.maxvalue waits forever 

} 
0
try 
{ 
    foreach(string command in S) // command is something like "c:\a.exe" 
    { 
     using(p = Process.Start(command)) 
     { 
     // I literally put nothing in here. 
     } 

    } 
} 
catch (Exception e) 
{ 
    // notify of process failure 
} 

कारण यह काम करता है क्योंकि जब अपवाद होता है, चर पी क्षेत्र से बाहर गिर जाता है और इस तरह यह निपटान विधि कहा जाता है बंद कर देता है कि प्रक्रिया है कि कैसे जाना होगा है। इसके अतिरिक्त, मुझे लगता है कि आप अगले आदेश पर जाने से पहले निष्पादन योग्य समाप्त होने की प्रतीक्षा करने के बजाय प्रत्येक आदेश के लिए थ्रेड को स्पिन करना चाहते हैं।

3

संदर्भ के लिए: IDisposable वस्तुओं के लिए कीवर्ड का उपयोग:

using(Writer writer = new Writer()) 
{ 
    writer.Write("Hello"); 
} 

सिर्फ संकलक है वाक्य - विन्यास। क्या यह करने के लिए नीचे संकलित है: के बाद से संकलक ब्लॉक का उपयोग अंदर लेखक संदर्भ फिर नियत करने से रोकता है

Writer writer = null; 
try 
{ 
    writer = new Writer(); 
    writer.Write("Hello"); 
} 
finally 
{ 
    if(writer != null) 
    { 
     ((IDisposable)writer).Dispose(); 
    } 
} 

using थोड़ा बेहतर है।

ढांचे दिशानिर्देश अनुभाग 9.3.1 पी। 256 राज्य:

निपटान() के अलावा) बंद (विधि उपलब्ध कराने पर विचार, अगर पास क्षेत्र में मानक शब्दावली है।


अपने कोड उदाहरण में, बाहरी कोशिश पकड़ अनावश्यक है (ऊपर देखें)।

संभवतः ऐसा नहीं कर रहा है जो आप यहां करना चाहते हैं क्योंकि निपटान() को p गुंजाइश से बाहर चला जाता है। यह प्रक्रिया (परीक्षण) बंद नहीं करता है।

प्रक्रियाएं स्वतंत्र हैं, इसलिए जब तक आप p.WaitForExit() पर कॉल नहीं करते हैं, वे अपने प्रोग्राम से पूरी तरह से स्वतंत्र होते हैं और अपनी खुद की चीज़ को स्वतंत्र करते हैं।

काउंटर-सहजता से, प्रक्रिया के लिए, बंद() केवल संसाधनों को रिलीज़ करता है लेकिन प्रोग्राम चलाता है। CloseMainWindow() कुछ प्रक्रियाओं के लिए काम कर सकता है, और Kill() किसी भी प्रक्रिया को मारने के लिए काम करेगा। CloseMainWindow() और Kill() दोनों अपवाद फेंक सकते हैं, इसलिए सावधान रहें यदि आप अंततः ब्लॉक में उनका उपयोग कर रहे हैं।

समाप्त करने के लिए, यहां कुछ कोड है जो प्रक्रियाओं को खत्म करने की प्रतीक्षा करता है लेकिन अपवाद होने पर प्रक्रियाओं को मार नहीं देता है। मैं यह नहीं कह रहा हूं कि यह ओरियन एडवर्ड्स से बेहतर है, बस अलग है।

List<System.Diagnostics.Process> processList = new List<System.Diagnostics.Process>(); 

try 
{ 
    foreach (string command in Commands) 
    { 
     processList.Add(System.Diagnostics.Process.Start(command)); 
    } 

    // loop until all spawned processes Exit normally. 
    while (processList.Any()) 
    { 
     System.Threading.Thread.Sleep(1000); // wait and see. 
     List<System.Diagnostics.Process> finished = (from o in processList 
                where o.HasExited 
                select o).ToList(); 

     processList = processList.Except(finished).ToList(); 
     foreach (var p in finished) 
     { 
      // could inspect exit code and exit time. 
      // note many properties are unavailable after process exits 
      p.Close(); 
     } 
    } 
} 
catch (Exception ex) 
{ 
    // log the exception 
    throw; 
} 
finally 
{ 
    foreach (var p in processList) 
    { 
     if (p != null) 
     { 
      //if (!p.HasExited) 
      // processes will still be running 
      // but CloseMainWindow() or Kill() can throw exceptions 
      p.Dispose(); 
     } 

    } 
} 

मैंने प्रक्रियाओं को मारने के लिए मार डाला नहीं है क्योंकि कोड शुरू होता है क्योंकि कोड भी शुरू होता है। अधिक जानकारी के लिए msdn दस्तावेज़ीकरण पढ़ें।

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