সিটিতে সিটিআরএল-সি ধরুন


158

কিভাবে এক ক্যাচ করে Ctrl+ + Cসি?


5
সিতে সিগন্যাল ধরার মতো কোনও জিনিস নেই .... বা কমপক্ষে তাই আমি সি 99 মান না পড়া পর্যন্ত ভেবেছিলাম। দেখা যাচ্ছে যে সিটিতে সংকেত হ্যান্ডলিং সংজ্ঞায়িত হয়েছে তবে সিটিআরএল-সি কোনও নির্দিষ্ট সংকেত বা সিগন্যাল তৈরি করার জন্য বাধ্যতামূলক নয়। আপনার প্ল্যাটফর্মের উপর নির্ভর করে এটি অসম্ভব হতে পারে।
জেরেমিপ

1
সিগন্যাল হ্যান্ডলিং বেশিরভাগ বাস্তবায়ন নির্ভর। * নিক্স প্ল্যাটফর্মগুলিতে <সিগন্যাল।> ব্যবহার করুন এবং আপনি ওএসএক্স এ থাকলে জিনিসগুলি আরও সহজ করতে আপনি জিসিডির সুবিধা নিতে পারেন ~
ডিলান লুকস

উত্তর:


205

একটি সিগন্যাল হ্যান্ডলার সহ।

এখানে boolব্যবহৃত একটি উল্টানো একটি সাধারণ উদাহরণ main():

#include <signal.h>

static volatile int keepRunning = 1;

void intHandler(int dummy) {
    keepRunning = 0;
}

// ...

int main(void) {

   signal(SIGINT, intHandler);

   while (keepRunning) { 
      // ...

জুন 2017 এ সম্পাদনা করুন : যার জন্য এটি উদ্বিগ্ন হতে পারে, বিশেষত যারা এই উত্তরটি সম্পাদনা করার জন্য অযৌক্তিক তাগিদ সহ। দেখুন, আমি এই উত্তরটি সাত বছর আগে লিখেছি । হ্যাঁ, ভাষার মান পরিবর্তন হয়। আপনি যদি সত্যিই বিশ্বের উন্নত করতে চান তবে দয়া করে আপনার নতুন উত্তর যুক্ত করুন তবে আমার মতো করুন। যেহেতু উত্তরটিতে আমার নাম রয়েছে, আমি এটি আমার শব্দগুলিকেও ধারণ করতে পছন্দ করব। ধন্যবাদ.


2
আসুন আমরা উল্লেখ করতে পারি যে এটি কাজ করার জন্য আমাদের # অন্তর্ভুক্ত <সিগন্যাল।
kristianlm

13
স্থির এটি bool volatile keepRunning = true;100% নিরাপদ হওয়া উচিত । সংকলক keepRunningএকটি রেজিস্টারে ক্যাশে নিখরচায় রয়েছে এবং উদ্বায়ী এটিকে প্রতিরোধ করবে। অনুশীলনে এটি সম্ভবত অস্থায়ী কীওয়ার্ড ব্যতীত কাজ করতে পারে যখন যখন লুপ কমপক্ষে একটি অ-ইনলাইন ফাংশন কল করে।
জোহানেস ওভারম্যান

2
@ ডর্কএডেলবুয়েটেল আমি সংশোধন করে দাঁড়িয়েছি, আমি ভেবেছিলাম আমার উন্নতিগুলি আপনার মূল উদ্দেশ্যগুলি আরও প্রতিফলিত করবে, দুঃখিত যদি তা না ঘটে তবে। যাইহোক, বৃহত্তর সমস্যাটি হ'ল যেহেতু আপনার উত্তরটি যথেষ্ট জেনারিক হওয়ার চেষ্টা করে এবং আইএমওর কারণ এটির একটি স্নিপেট সরবরাহ করা উচিত যা অ্যাসিঙ্ক্রোনাস বিঘ্নের অধীনেও কাজ করছে: আমি হয় সেখানে ব্যবহার করব sig_atomic_tবা atomic_boolটাইপ করব। আমি কেবল সেটিকে মিস করেছি। এখন, যেহেতু আমরা কথা বলছি: আপনি কি আমার সর্বশেষ সম্পাদনাটি রোলব্যাক করতে চান? কোনও শক্ত অনুভূতিই এটি আপনার দৃষ্টিকোণ থেকে পুরোপুরি
উপলব্ধিযোগ্য হবে

2
এটা অনেক ভাল!
ডার্ক এডেলবুয়েটেল

2
@ জোহানেস ওভারম্যান এই নয় যে আমি নিতপিক করতে চাই তবে কঠোরভাবে বলতে চাই, কোডটি কোনও অ-ইনলাইন ফাংশন কল করে কিনা তা বিবেচনাধীন নয়, কেবল কোনও মেমরি বাধা পেরোনোর ​​সময়ই সংকলককে ক্যাশেড মানের উপর নির্ভর করতে দেওয়া হয় না। কোনও মিউটেক্সকে লক করা / আনলক করা এমন মেমরির বাধা হয়ে দাঁড়াবে। যেহেতু ভেরিয়েবলটি স্থিতিশীল এবং সুতরাং বর্তমান ফাইলের বাইরে দৃশ্যমান নয়, সংকলকটি ধরে নিতে নিরাপদ যে কোনও ফাংশন কখনও তার মান পরিবর্তন করতে পারে না, যদি না আপনি ফাংশনে সেই পরিবর্তনশীলটির কোনও রেফারেন্স না দিয়ে দেন। সুতরাং যে কোনও ক্ষেত্রে এখানে অস্থির দৃ strongly়ভাবে পরামর্শ দেওয়া হচ্ছে।
মেকি

47

এখানে চেক করুন:

দ্রষ্টব্য: স্পষ্টতই, হ্যান্ডলারটি কীভাবে সেটআপ করা যায় সে সম্পর্কে এটি ব্যাখ্যা করার একটি সহজ উদাহরণ CtrlC, তবে সর্বদা নিয়ম রয়েছে যা অন্য কোনও কিছু ভঙ্গ না করার জন্য মেনে চলতে হবে। নীচের মন্তব্য পড়ুন।

উপরে থেকে নমুনা কোড:

#include  <stdio.h>
#include  <signal.h>
#include  <stdlib.h>

void     INThandler(int);

int  main(void)
{
     signal(SIGINT, INThandler);
     while (1)
          pause();
     return 0;
}

void  INThandler(int sig)
{
     char  c;

     signal(sig, SIG_IGN);
     printf("OUCH, did you hit Ctrl-C?\n"
            "Do you really want to quit? [y/n] ");
     c = getchar();
     if (c == 'y' || c == 'Y')
          exit(0);
     else
          signal(SIGINT, INThandler);
     getchar(); // Get new line character
}

2
@ ডেরিক সম্মতি, int mainএকটি যথাযথ জিনিস, gccএবং অন্যান্য সংকলকগণ 1990 এর দশক থেকে এটি সঠিকভাবে চলমান প্রোগ্রামগুলিতে সংকলন করে। এখানে বেশ ভালভাবে ব্যাখ্যা করা হয়েছে: eskimo.com/~scs/readings/voidmain.960823.html - এটি মূলত একটি "বৈশিষ্ট্য", আমি এটি এর মতো নিই।
ircrock.com

1
@ আইসিরোক ডট কম: সমস্ত সত্য (সি-এ শূন্য মূল সম্পর্কে), তবে প্রকাশ্যে পোস্ট করার সময় সম্ভবত ইন মেইন () ব্যবহার করে বিতর্ক পুরোপুরি এড়ানো ভাল হয় যে এটি তেমন মূল পয়েন্ট থেকে বিরক্ত না হয়।
ক্লিফোর্ড

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

2
@ আইসিরক ডট কম: সিগন্যাল হ্যান্ডলারে জটিল কিছু করা মাথা ব্যথার কারণ হতে পারে। বিশেষত আইও সিস্টেম ব্যবহার করে।
মার্টিন ইয়র্ক

2
@ স্ট্যাকার ধন্যবাদ - আমি মনে করি এটি শেষে এটি মূল্যবান ভবিষ্যতে যদি কেউ এই কোডটি জুড়ে হোঁচট খায় তবে প্রশ্নের বিষয় নির্বিশেষে এটিকে যথাসম্ভব সঠিকভাবে করা ভাল।
icyrock.com

30

ইউএন * এক্স প্ল্যাটফর্ম সম্পর্কিত সংযোজন।

signal(2)জিএনইউ / লিনাক্সের ম্যান পেজ অনুসারে , আচরণটি signalযেমন আচরণের মতো বহনযোগ্য নয় তেমন sigaction:

সিগন্যালের () ব্যবহারটি ইউনিক্স সংস্করণে পৃথক হয়ে থাকে এবং লিনাক্সের বিভিন্ন সংস্করণেও historতিহাসিকভাবে বৈচিত্র রয়েছে। এর ব্যবহার এড়িয়ে চলুন: পরিবর্তে সিগিয়েশন (2) ব্যবহার করুন।

সিস্টেম ভিতে, সিস্টেমটি সিগন্যালের আরও উদাহরণগুলির সরবরাহ সরবরাহকে অবরুদ্ধ করে না এবং একটি সংকেতের বিতরণ হ্যান্ডলারটিকে ডিফল্টরূপে পুনরায় সেট করে। বিএসডিতে শব্দার্থবিজ্ঞানের পরিবর্তন ঘটে।

ডির্ক এডেলবুয়েটেলের sigactionপরিবর্তে পূর্ববর্তী উত্তরের নিম্নলিখিত পরিবর্তনের ব্যবহারগুলি পরিবর্তে signal:

#include <signal.h>
#include <stdlib.h>

static bool keepRunning = true;

void intHandler(int) {
    keepRunning = false;
}

int main(int argc, char *argv[]) {
    struct sigaction act;
    act.sa_handler = intHandler;
    sigaction(SIGINT, &act, NULL);

    while (keepRunning) {
        // main loop
    }
}


14

অথবা আপনি টার্মিনালটি কাঁচা মোডে রাখতে পারেন:

struct termios term;

term.c_iflag |= IGNBRK;
term.c_iflag &= ~(INLCR | ICRNL | IXON | IXOFF);
term.c_lflag &= ~(ICANON | ECHO | ECHOK | ECHOE | ECHONL | ISIG | IEXTEN);
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
tcsetattr(fileno(stdin), TCSANOW, &term);

এখন ব্যবহার করে Ctrl+ Cকীস্ট্রোকগুলি পড়া সম্ভব হবে fgetc(stdin)। এটি ব্যবহার করা থেকে সাবধান থাকুন কারণ আপনি সাধারণত Ctrl++ Z, Ctrl+ Q, Ctrl+ Sইত্যাদি পারেন না।


11

একটি ফাঁদ সেট আপ করুন (আপনি একটি হ্যান্ডলারের সাহায্যে কয়েকটি সিগন্যাল ফাঁদে ফেলতে পারেন):

সিগন্যাল (SIGQUIT, আমার_হ্যান্ডলার);
সিগন্যাল (SIGINT, আমার_হ্যান্ডলার);

আপনি চাইলে সিগন্যালটি পরিচালনা করুন, তবে সীমাবদ্ধতা এবং গোটচাস সম্পর্কে সচেতন থাকুন:

অকার্যকর আমার_হ্যান্ডলার (ইন সিগ)
{
  / * আপনার কোড এখানে। * /
}

8

@ পিটার ভারো ড र्कের উত্তর আপডেট করেছেন, কিন্তু ডার্ক এই পরিবর্তনটি প্রত্যাখ্যান করেছেন। পিটারের নতুন উত্তরটি এখানে:

যদিও উপরের স্নিপেটটি সঠিক উদাহরণস্বরূপ, যদি আরও সম্ভব হয় তবে যদি সম্ভব হয় তবে পরবর্তী মানগুলির দ্বারা সরবরাহ করা আরও আধুনিক ধরণের এবং গ্যারান্টি ব্যবহার করা উচিত। সুতরাং, এখানে যারা সন্ধান করছেন তাদের জন্য এখানে একটি নিরাপদ এবং আধুনিক বিকল্প এবং অনুসারে বাস্তবায়ন:

#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

static volatile sig_atomic_t keep_running = 1;

static void sig_handler(int _)
{
    (void)_;
    keep_running = 0;
}

int main(void)
{
    signal(SIGINT, sig_handler);

    while (keep_running)
        puts("Still running...");

    puts("Stopped by signal `SIGINT'");
    return EXIT_SUCCESS;
}

সি 11 স্ট্যান্ডার্ড: 7.14§2 শিরোনাম <signal.h>একটি প্রকার ঘোষণা করে ... sig_atomic_tযা অণু সত্তা হিসাবে অ্যাকসন ক্রোনার উপস্থিতিতে এমনকি কোনও অণু সত্তা হিসাবে অ্যাক্সেস করা যায় এমন কোনও সামগ্রীর (সম্ভবত উদ্বায়ী-যোগ্য) পূর্ণসংখ্যা টাইপ।

উপরন্তু:

সি 11 স্ট্যান্ডার্ড: 7.14.1.1§§5 যদি সিগন্যালটি abortবা raiseফাংশন কল করার ফলাফল ব্যতীত অন্য কোনও ঘটনা ঘটে থাকে তবে সিগন্যাল হ্যান্ডলার এমন কোনও বিষয়কে staticবা থ্রেড স্টোরেজ সময়কালকে বোঝায় যা অন্য কোনও লক-মুক্ত পারমাণবিক বস্তু নয় is হিসাবে ঘোষিত কোনও বস্তুর মান নির্ধারণের চেয়ে volatile sig_atomic_t...


আমি বেড়ান না (void)_;... এর উদ্দেশ্য কী? এটি কি তাই যে সংকলকটি অব্যবহৃত পরিবর্তনশীল সম্পর্কে সতর্ক করে না?
লুইস পাওলো


আমি সবেমাত্র উত্তরটি পেয়েছি এবং সেই লিঙ্কটি এখানে পেস্ট করতে চলেছি! ধন্যবাদ :)
লুইস পাওলো

5

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


3
#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void sig_handler(int signo)
{
  if (signo == SIGINT)
    printf("received SIGINT\n");
}

int main(void)
{
  if (signal(SIGINT, sig_handler) == SIG_ERR)
  printf("\ncan't catch SIGINT\n");
  // A long long wait so that we can easily issue a signal to this process
  while(1) 
    sleep(1);
  return 0;
}

সিগ_হ্যান্ডলার ফাংশনটি পরীক্ষা করে যদি পাস করা আর্গুমেন্টের মান SIGINT এর সমান হয়, তবে মুদ্রণটি কার্যকর হবে।


সিগন্যাল হ্যান্ডলারে কখনই I / O রুটিনগুলি কল করবেন না।
jwdonahue

2

প্রস্থান করার আগে এটি কেবল মুদ্রণ করুন।

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void sigint_handler(int);

int  main(void)
{
    signal(SIGINT, sigint_handler);

     while (1){
         pause();   
     }         
    return 0;
}

 void sigint_handler(int sig)
{
    /*do something*/
    printf("killing process %d\n",getpid());
    exit(0);
}

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