আমি কীভাবে একটি সি # কনসোল অ্যাপে সিটিআরএল-সি (সিগিন্ট) ফাঁদ করব?


221

আমি সি # কনসোল অ্যাপ্লিকেশনটিতে CTRL+ ফাঁদে ফেলতে সক্ষম হতে চাই Cযাতে প্রস্থান করার আগে আমি কিছু ক্লিনআপগুলি করতে পারি। এটি করার সর্বোত্তম উপায় কী?

উত্তর:


126

6
প্রকৃতপক্ষে, নিবন্ধটি পি / ইনভোকের পরামর্শ দেয় এবং CancelKeyPressমন্তব্যে কেবল সংক্ষেপে উল্লেখ করা হয়েছে। একটি ভাল নিবন্ধ কোডেনভারলিখন.com
2006/

এটি কাজ করে তবে এটি এক্স দিয়ে উইন্ডোটি বন্ধ করে আটকাবে না below নীচে আমার সম্পূর্ণ সমাধান দেখুন। কিল পাশাপাশি কাজ করে
JJ_Coder4Hire

1
আমি খুঁজে পেয়েছি যে কনসোলটি বন্ধ থাকলে কনসোল.ক্যানসেলকিপ্রেস কাজ করা বন্ধ করবে। সিস্টেমেড সহ মনো / লিনাক্সের অধীনে একটি অ্যাপ্লিকেশন চালনা করা বা অ্যাপ্লিকেশনটিকে "মনো মাইএপ.এক্সে </ dev / নাল" হিসাবে চালানো হলে ডিফল্ট সিগন্যাল হ্যান্ডলারের কাছে একটি সিগিন্ট প্রেরণ করা হবে এবং তাত্ক্ষণিকভাবে অ্যাপটিকে হত্যা করবে। Linux ব্যবহারকারীরা দেখতে চাইবেন stackoverflow.com/questions/6546509/...
tekHedd

2
@ বিজেএলএম এর মন্তব্যের জন্য অ-ভাঙা লিংক: web.archive.org/web/20110424085511/http://…
ইয়ান কেম্প

প্রক্রিয়া অভদ্রতা ছাড়ার আগে আপনাকে সাইন্টটিতে সাড়া দেওয়ার মতো পরিমাণ নেই? আমি এটি কোথাও খুঁজে পাচ্ছি না এবং আমি কোথায় পড়েছি তা স্মরণ করার চেষ্টা করছি।
জন জাব্রোস্কি

223

Console.CancelKeyPress ইভেন্ট এই জন্য ব্যবহৃত হয়। এটি এটি ব্যবহার করা হয়:

public static void Main(string[] args)
{
    Console.CancelKeyPress += delegate {
        // call methods to clean up
    };

    while (true) {}
}

যখন ব্যবহারকারী Ctrl + C টিপেন তখন ডেলিগেটের কোডটি চালানো হয় এবং প্রোগ্রামটি প্রস্থান হয়। এটি আপনাকে প্রয়োজনীয় পদ্ধতিগুলিতে কল করে ক্লিনআপ সম্পাদন করতে দেয়। নোট করুন যে প্রতিনিধি কার্যকর হওয়ার পরে কোনও কোড নেই।

অন্যান্য পরিস্থিতি রয়েছে যেখানে এটি কাটবে না। উদাহরণস্বরূপ, যদি প্রোগ্রামটি বর্তমানে গুরুত্বপূর্ণ গণনা সম্পাদন করে যা অবিলম্বে বন্ধ করা যায় না। সেক্ষেত্রে সঠিক কৌশলটি হ'ল গণনাটি শেষ হওয়ার পরে প্রোগ্রামটি থেকে বেরিয়ে আসতে বলুন। নিম্নলিখিত কোডটি কীভাবে এটি প্রয়োগ করা যেতে পারে তার একটি উদাহরণ দেয়:

class MainClass
{
    private static bool keepRunning = true;

    public static void Main(string[] args)
    {
        Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
            e.Cancel = true;
            MainClass.keepRunning = false;
        };

        while (MainClass.keepRunning) {
            // Do your work in here, in small chunks.
            // If you literally just want to wait until ctrl-c,
            // not doing anything, see the answer using set-reset events.
        }
        Console.WriteLine("exited gracefully");
    }
}

এই কোড এবং প্রথম উদাহরণের মধ্যে পার্থক্যটি এটি e.Cancelসত্য হিসাবে সেট করা হয়, যার অর্থ ডেলিগেটের পরে মৃত্যুদন্ড কার্যকর হয়। রান পারেন, জন্য Ctrl + সি প্রেস ব্যবহারকারী যখন এটি ঘটে জন্য প্রোগ্রাম অপেক্ষা করছে keepRunningপরিবর্তনশীল পরিবর্তন মান যা প্রস্থান করার সময় লুপ ঘটায়। এই প্রোগ্রামটি করুণভাবে প্রস্থান করার একটি উপায়।


21
keepRunningচিহ্নিত করা প্রয়োজন হতে পারে volatile। মূল থ্রেড এটি অন্যথায় সিপিইউ রেজিস্টারে ক্যাশে রাখতে পারে এবং ডেলিগেটের মৃত্যুদন্ড কার্যকর করার সময় মান পরিবর্তন লক্ষ্য করে না।
cdowie

এটি কাজ করে তবে এটি এক্স দিয়ে উইন্ডোটি বন্ধ করে আটকাবে না below নীচে আমার সম্পূর্ণ সমাধান দেখুন। পাশাপাশি খুন কাজ করে।
জেজে_ কোডার

13
একটি ManualResetEventস্পিন পরিবর্তে একটি ব্যবহার করার জন্য পরিবর্তন করা উচিত bool
মিজিপজোর 14

গিট-ব্যাশ, এমএসওয়াইএস 2 বা সাইগউইনে চলমান স্টাফ চালানো অন্য কারোর জন্য একটি ছোট সতর্কতা: এটি কাজ করার জন্য আপনাকে উইন্টপির মাধ্যমে ডটনেট চালাতে হবে (সুতরাং winpty dotnet run) , অন্যথায়, প্রতিনিধি চালানো হবে না।
স্যামুয়েল লাম্পা

নজর রাখুন- বাতিল করাপ্রেস-এর ইভেন্টটি একটি থ্রেড পুলের থ্রেডে পরিচালিত হয়েছে, যা তাৎক্ষণিকভাবে সুস্পষ্ট নয়: ডকস.মাইক্রোসফটকম
স্যাম রুয়েবি

100

আমি জোনাসের উত্তরে যুক্ত করতে চাই । একটি উপর স্পিনিং bool100% সিপিইউ ব্যবহারের কারণ ঘটায় এবং CTRL+ এর জন্য অপেক্ষা করার সময় প্রচুর পরিমাণে শক্তি অপচয় করে C

ভাল সমাধান একটি ব্যবহার করা ManualResetEventআসলে জন্য "অপেক্ষা" করার CTRL+ + C:

static void Main(string[] args) {
    var exitEvent = new ManualResetEvent(false);

    Console.CancelKeyPress += (sender, eventArgs) => {
                                  eventArgs.Cancel = true;
                                  exitEvent.Set();
                              };

    var server = new MyServer();     // example
    server.Run();

    exitEvent.WaitOne();
    server.Stop();
}

28
আমি মনে করি বিন্দুটি হ'ল আপনি যখন লুপটির অভ্যন্তরে সমস্ত কাজ করবেন, এবং সিটিআরএল + সি আঘাত হবেন তখন পুনরাবৃত্তির মাঝখানে ভাঙবে না; এটি ভাঙ্গনের আগে সেই পুনরাবৃত্তিটি সম্পন্ন করবে।
pkr298

2
@ pkr298 - খুব খারাপ লোক আপনার মন্তব্যটি সম্পূর্ণ সত্য না বলে ভোট দেয় না। আমি জোনাসকে যেভাবে জনাথন করেছিলেন (যেটা সহজাতভাবে খারাপ নয় তবে জোনাস তার উত্তরকে বোঝায় তাই নয়) থেকে মানুষকে স্পষ্ট করার জন্য তার উত্তরটি সম্পাদনা করব
এম মিম্পেন

এই উন্নতি সহ বিদ্যমান উত্তর আপডেট করুন।
মিজিপজোর 14

27

এখানে একটি সম্পূর্ণ কাজের উদাহরণ। খালি সি # কনসোল প্রকল্পে আটকান:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace TestTrapCtrlC {
    public class Program {
        static bool exitSystem = false;

        #region Trap application termination
        [DllImport("Kernel32")]
        private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);

        private delegate bool EventHandler(CtrlType sig);
        static EventHandler _handler;

        enum CtrlType {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT = 1,
            CTRL_CLOSE_EVENT = 2,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT = 6
        }

        private static bool Handler(CtrlType sig) {
            Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown");

            //do your cleanup here
            Thread.Sleep(5000); //simulate some cleanup delay

            Console.WriteLine("Cleanup complete");

            //allow main to run off
            exitSystem = true;

            //shutdown right away so there are no lingering threads
            Environment.Exit(-1);

            return true;
        }
        #endregion

        static void Main(string[] args) {
            // Some biolerplate to react to close window event, CTRL-C, kill, etc
            _handler += new EventHandler(Handler);
            SetConsoleCtrlHandler(_handler, true);

            //start your multi threaded program here
            Program p = new Program();
            p.Start();

            //hold the console so it doesn’t run off the end
            while (!exitSystem) {
                Thread.Sleep(500);
            }
        }

        public void Start() {
            // start a thread and start doing some processing
            Console.WriteLine("Thread started, processing..");
        }
    }
}

8
এই পি / আহ্বান তাই
ক্রস প্ল্যাটফর্ম

আমি কেবল এটি আরও যুক্ত করেছি কারণ এটিই একমাত্র উত্তর যা সম্পূর্ণ উত্তরকে সম্বোধন করে। এটি একটি সম্পূর্ণরূপে এবং আপনাকে কোনও কার্যকারিতা জড়িত ছাড়াই টাস্ক শিডিয়ুলারের অধীনে প্রোগ্রামটি চালানোর অনুমতি দেয়। আপনি এখনও পরিষ্কার করার সুযোগ পান। আপনার প্রকল্পে এনএলওজি ব্যবহার করুন এবং আপনার ম্যানেজ করার মতো কিছু আছে। আমি বিস্মিত হয়েছি যে এটি নেট কোর 2 বা 3 সংকলন করবে
বিগটিফ্রমেজেড

7

এই প্রশ্নটি খুব অনুরূপ:

কনসোল প্রস্থান C # ক্যাপচার করুন

এখানে আমি এই সমস্যাটি কীভাবে সমাধান করেছি এবং এক্সটি এবং সিটিআরএল-সি-তে আঘাতকারী ব্যবহারকারীর সাথেও আচরণ করেছি। ম্যানুয়ালসেটসেন্টস এর ব্যবহার লক্ষ্য করুন। এগুলি মূল থ্রেডকে ঘুমিয়ে দেবে যা প্রস্থান বা ক্লিনআপের অপেক্ষার সময় সিপিইউকে অন্যান্য থ্রেডগুলি প্রক্রিয়া করতে মুক্ত করে। দ্রষ্টব্য: মূলটির শেষে টার্মিনেশন কমপ্লিটড এভেন্ট সেট করা প্রয়োজন। অ্যাপ্লিকেশনটি মারার সময় ওএসের সময় নির্ধারিত হওয়ার কারণে এটির ব্যর্থতা সমাপ্তিতে অপ্রয়োজনীয় বিলম্ব ঘটায়।

namespace CancelSample
{
    using System;
    using System.Threading;
    using System.Runtime.InteropServices;

    internal class Program
    {
        /// <summary>
        /// Adds or removes an application-defined HandlerRoutine function from the list of handler functions for the calling process
        /// </summary>
        /// <param name="handler">A pointer to the application-defined HandlerRoutine function to be added or removed. This parameter can be NULL.</param>
        /// <param name="add">If this parameter is TRUE, the handler is added; if it is FALSE, the handler is removed.</param>
        /// <returns>If the function succeeds, the return value is true.</returns>
        [DllImport("Kernel32")]
        private static extern bool SetConsoleCtrlHandler(ConsoleCloseHandler handler, bool add);

        /// <summary>
        /// The console close handler delegate.
        /// </summary>
        /// <param name="closeReason">
        /// The close reason.
        /// </param>
        /// <returns>
        /// True if cleanup is complete, false to run other registered close handlers.
        /// </returns>
        private delegate bool ConsoleCloseHandler(int closeReason);

        /// <summary>
        ///  Event set when the process is terminated.
        /// </summary>
        private static readonly ManualResetEvent TerminationRequestedEvent;

        /// <summary>
        /// Event set when the process terminates.
        /// </summary>
        private static readonly ManualResetEvent TerminationCompletedEvent;

        /// <summary>
        /// Static constructor
        /// </summary>
        static Program()
        {
            // Do this initialization here to avoid polluting Main() with it
            // also this is a great place to initialize multiple static
            // variables.
            TerminationRequestedEvent = new ManualResetEvent(false);
            TerminationCompletedEvent = new ManualResetEvent(false);
            SetConsoleCtrlHandler(OnConsoleCloseEvent, true);
        }

        /// <summary>
        /// The main console entry point.
        /// </summary>
        /// <param name="args">The commandline arguments.</param>
        private static void Main(string[] args)
        {
            // Wait for the termination event
            while (!TerminationRequestedEvent.WaitOne(0))
            {
                // Something to do while waiting
                Console.WriteLine("Work");
            }

            // Sleep until termination
            TerminationRequestedEvent.WaitOne();

            // Print a message which represents the operation
            Console.WriteLine("Cleanup");

            // Set this to terminate immediately (if not set, the OS will
            // eventually kill the process)
            TerminationCompletedEvent.Set();
        }

        /// <summary>
        /// Method called when the user presses Ctrl-C
        /// </summary>
        /// <param name="reason">The close reason</param>
        private static bool OnConsoleCloseEvent(int reason)
        {
            // Signal termination
            TerminationRequestedEvent.Set();

            // Wait for cleanup
            TerminationCompletedEvent.WaitOne();

            // Don't run other handlers, just exit.
            return true;
        }
    }
}

3

Console.TreatControlCAsInput = true; আমার জন্য কাজ করেছে।


2
এটি প্রতিটি ইনপুটটির জন্য রিডলাইনকে দুটি এন্টার প্রেসের প্রয়োজন হতে পারে।
গ্রেট

0

বাইরে বেরোনোর ​​আগে আমি কিছু ক্লিনআপ করতে পারি। এটি করার সর্বোত্তম উপায়টি হ'ল আসল লক্ষ্য: নিজের নিজের জিনিস তৈরির জন্য ফাঁদ থেকে বেরিয়ে আসা। এবং উপরের নীগ্রহের উত্তরগুলি এটি সঠিক করে না তোলে। কারণ, অ্যাপটি প্রস্থান করার জন্য Ctrl + C হ'ল এক উপায়।

ডটনেট সি # তে এর জন্য কী প্রয়োজন - তথাকথিত বাতিলকরণ টোকেনটি প্রেরণ করা হয় Host.RunAsync(ct)এবং তারপরে, প্রস্থান সিগন্যালের ফাঁদে, উইন্ডোজের জন্য এটি হবে

    private static readonly CancellationTokenSource cts = new CancellationTokenSource();
    public static int Main(string[] args)
    {
        // For gracefull shutdown, trap unload event
        AppDomain.CurrentDomain.ProcessExit += (sender, e) =>
        {
            cts.Cancel();
            exitEvent.Wait();
        };

        Console.CancelKeyPress += (sender, e) =>
        {
            cts.Cancel();
            exitEvent.Wait();
        };

        host.RunAsync(cts);
        Console.WriteLine("Shutting down");
        exitEvent.Set();
        return 0;
     }

...

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.