.NET कंसोल ऐप को कैसे चालू रखें?


104

कंसोल एप्लिकेशन पर विचार करें जो कुछ सेवाओं को एक अलग थ्रेड में शुरू करता है। इसे बंद करने के लिए उपयोगकर्ता को Ctrl + C दबाने की प्रतीक्षा करनी होगी।

निम्नलिखित में से कौन सा ऐसा करने का बेहतर तरीका है?

static ManualResetEvent _quitEvent = new ManualResetEvent(false);

static void Main() {
    Console.CancelKeyPress += (sender, eArgs) => {
        _quitEvent.Set();
        eArgs.Cancel = true;
    };

    // kick off asynchronous stuff 

    _quitEvent.WaitOne();

    // cleanup/shutdown and quit
}

या यह, थ्रेड का उपयोग करना। सो (1):

static bool _quitFlag = false;

static void Main() {
    Console.CancelKeyPress += delegate {
        _quitFlag = true;
    };

    // kick off asynchronous stuff 

    while (!_quitFlag) {
        Thread.Sleep(1);
    }

    // cleanup/shutdown and quit
}

जवाबों:


63

आप हमेशा लूप का उपयोग करना रोकना चाहते हैं, खासकर जब आप कोड को चर को रीचार्ज करने के लिए मजबूर कर रहे हों। यह CPU संसाधनों को बर्बाद करता है और आपके प्रोग्राम को धीमा कर देता है।

मैं पहले वाला जरूर कहूंगा।


2
+1। इसके अलावा, चूंकि boolघोषित नहीं किया गया है volatile, इस बात की निश्चित संभावना है कि बाद _quitFlagमें whileलूप में पढ़ी जाने वाली सामग्री को अनुकूलित किया जाएगा, जिससे अनंत लूप बन जाएगा।
एडम रॉबिन्सन

2
ऐसा करने के लिए अनुशंसित तरीका गुम है। मैं एक जवाब के रूप में यह उम्मीद कर रहा था।
इयूरी डॉस अंजोस

30

वैकल्पिक रूप से, एक और अधिक सरल समाधान है:

Console.ReadLine();

मैं यह सुझाव देने वाला था, लेकिन यह केवल Ctrl-C
थॉमस लेवेस्क

मुझे आभास हुआ कि CTRL-C सिर्फ एक उदाहरण था - किसी भी उपयोगकर्ता को इसे बंद करने के लिए इनपुट
Cocowalla

याद रखें कि 'Console.ReadLine ()' थ्रेड ब्लॉकिंग है। तो आवेदन अभी भी चल रहा है, लेकिन उपयोगकर्ता लाइन में प्रवेश करने की प्रतीक्षा करने के अलावा कुछ नहीं कर रहा है
fabriciorissetto

2
@fabriciorissetto ओपी प्रश्न में कहा गया है कि 'अतुल्यकालिक सामान को लात मारें', इसलिए आवेदन दूसरे धागे पर काम करेगा
Cocowalla

1
@Cocowalla मैं चूक गया। मेरी गलती!
फैब्रिकोरिसिट्टो

12

आप ऐसा कर सकते हैं (और CancelKeyPressईवेंट हैंडलर को हटा दें ):

while(!_quitFlag)
{
    var keyInfo = Console.ReadKey();
    _quitFlag = keyInfo.Key == ConsoleKey.C
             && keyInfo.Modifiers == ConsoleModifiers.Control;
}

यकीन नहीं है कि अगर यह बेहतर है, लेकिन मुझे Thread.Sleepलूप में कॉल करने का विचार पसंद नहीं है .. मुझे लगता है कि यह उपयोगकर्ता इनपुट पर ब्लॉक करने के लिए क्लीनर है।


मुझे यह पसंद नहीं है कि आप Ctrl + C द्वारा ट्रिगर किए गए सिग्नल के बजाय, Ctrl + C की जांच कर रहे हैं।
कोडइन्चोस

9

मैं Application.Run का उपयोग करना पसंद करता हूं

static void Main(string[] args) {

   //Do your stuff here

   System.Windows.Forms.Application.Run();

   //Cleanup/Before Quit
}

डॉक्स से:

एक फार्म के बिना, वर्तमान थ्रेड पर एक मानक अनुप्रयोग संदेश लूप चलाने शुरू होता है।


9
लेकिन फिर आप सिर्फ इसके लिए विंडोज फॉर्म पर निर्भरता लेते हैं। पारंपरिक .NET फ्रेमवर्क के साथ बहुत अधिक समस्या नहीं है, लेकिन वर्तमान रुझान केवल उन हिस्सों सहित मॉड्यूलर परिनियोजन की ओर है जिनकी आपको आवश्यकता है।
कोडइन्चोस

4

लगता है जैसे आप इसे जरूरत से ज्यादा कठिन बना रहे हैं। Joinइसे बंद करने का संकेत देने के बाद सिर्फ थ्रेड ही क्यों ?

class Program
{
    static void Main(string[] args)
    {
        Worker worker = new Worker();
        Thread t = new Thread(worker.DoWork);
        t.IsBackground = true;
        t.Start();

        while (true)
        {
            var keyInfo = Console.ReadKey();
            if (keyInfo.Key == ConsoleKey.C && keyInfo.Modifiers == ConsoleModifiers.Control)
            {
                worker.KeepGoing = false;
                break;
            }
        }
        t.Join();
    }
}

class Worker
{
    public bool KeepGoing { get; set; }

    public Worker()
    {
        KeepGoing = true;
    }

    public void DoWork()
    {
        while (KeepGoing)
        {
            Console.WriteLine("Ding");
            Thread.Sleep(200);
        }
    }
}

2
मेरे मामले में मैं उन थ्रेड्स को नियंत्रित नहीं करता जो अतुल्यकालिक सामान पर चलता है।
ऑर्बिट

1) मुझे यह पसंद नहीं है कि आप Ctrl + C द्वारा ट्रिगर किए गए सिग्नल के बजाय, Ctrl + C की जांच कर रहे हैं। 2) आपका दृष्टिकोण काम नहीं करता है यदि एप्लिकेशन एकल कार्यकर्ता थ्रेड के बजाय कार्य का उपयोग करता है।
कोडइन्चोस

2

रद्दीकरण टोकन के आधार पर थ्रेड / प्रोग्राम को ब्लॉक करना भी संभव है।

token.WaitHandle.WaitOne();

टोकन रद्द होने पर WaitHandle को संकेत दिया जाता है।

मैंने इस तकनीक का उपयोग Microsoft.Azure.WebJobs.JobHost द्वारा देखा है, जहां टोकन WebJobsShutdownWatcher (नौकरी समाप्त करने वाला एक फ़ाइल देखने वाला) के रद्द करने के टोकन स्रोत से आता है।

यह कुछ नियंत्रण देता है जब कार्यक्रम समाप्त हो सकता है।


1
यह किसी भी वास्तविक दुनिया कंसोल ऐप के लिए एक उत्कृष्ट उत्तर है, जिसे सुनने की आवश्यकता है CTL+Cक्योंकि यह एक लंबे समय से चल रहे ऑपरेशन का प्रदर्शन कर रहा है, या एक डेमॉन है, जिसे अपने कार्यकर्ता थ्रेड्स को शालीनतापूर्वक बंद करना चाहिए। आप एक रद्द करें के साथ ऐसा करेंगे और इसलिए यह जवाब WaitHandleएक नया लाभ पैदा करने के बजाय पहले से मौजूद होगा।
mdisibio

1

दो में से पहला बेहतर है

_quitEvent.WaitOne();

क्योंकि दूसरे एक में धागा उठता है हर एक मिलीसेकंड ओएस रुकावट में बदल जाएगा जो महंगा है


यह Consoleविधियों के लिए एक अच्छा विकल्प है यदि आपके पास कंसोल संलग्न नहीं है (क्योंकि, उदाहरण के लिए, कार्यक्रम एक सेवा द्वारा शुरू किया गया है)
मार्को सुल

0

आपको इसे वैसे ही करना चाहिए जैसे आप एक विंडोज़ सेवा की प्रोग्रामिंग कर रहे थे। आप कभी भी एक बयान का उपयोग नहीं करेंगे इसके बजाय आप एक प्रतिनिधि का उपयोग करेंगे। WaitOne () का उपयोग आमतौर पर थ्रेड्स के निपटान के लिए प्रतीक्षा करते समय किया जाता है - Thread.Sleep () - यह अदृश्य नहीं है - क्या आपने System.Timers.Timers का उपयोग करने के बारे में सोचा है?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.