2012-05-26 22 views
7

मैं लिनक्स में सिग्नल का अध्ययन कर रहा हूं। और मैंने सिगिनट को पकड़ने के लिए एक टेस्ट प्रोग्राम किया है।क्यों लिनक्स हमेशा Ctrl + C दबाकर "^ सी" आउटपुट करता है?

#include <unistd.h> 
#include <signal.h> 
#include <iostream> 
void signal_handler(int signal_no); 
int main() { 
    signal(SIGINT, signal_handler); 
    for (int i = 0; i < 10; ++i) { 
    std::cout << "I'm sleeping..." << std::endl; 
    unsigned int one_ms = 1000; 
    usleep(200* one_ms); 
    } 
    return 0; 
} 
void signal_handler(int signal_no) { 
    if (signal_no == SIGINT) 
    std::cout << "Oops, you pressed Ctrl+C!\n"; 
    return; 
} 

उत्पादन इस तरह दिखता है जबकि:

I'm sleeping... 
I'm sleeping... 
^COops, you pressed Ctrl+C! 
I'm sleeping... 
I'm sleeping... 
^COops, you pressed Ctrl+C! 
I'm sleeping... 
^COops, you pressed Ctrl+C! 
I'm sleeping... 
^COops, you pressed Ctrl+C! 
I'm sleeping... 
^COops, you pressed Ctrl+C! 
I'm sleeping... 
I'm sleeping... 
I'm sleeping... 

मैं समझता हूँ कि जब Ctrl + C दबाने, अग्रभूमि प्रक्रिया समूह के सभी एक SIGINT प्राप्त करता है (कोई प्रक्रिया इसे अनदेखा करने के लिए चुनता है, तो) में संसाधित करता है।

तो क्या यह है कि खोल (बैश) और उपरोक्त कार्यक्रम के उदाहरण दोनों को सिग्नल प्राप्त हुआ? प्रत्येक "ओप्स" से पहले "^ सी" कहां से आता है?

ओएस सेंटोस है, और खोल बैश है।

उत्तर

9

यह टर्मिनल (चालक) कि^सी को बीच में रोक और एक संकेत (जो खोल है) stty intr ^B टर्मिनल हिदायत होगा जुड़ी प्रक्रिया के लिए भेजा करने के लिए इसकी अनुवाद है चालक को इसके बजाय^बी को अवरुद्ध करने के लिए। यह टर्मिनल ड्राइवर भी है जो^सी को टर्मिनल पर वापस ले जाता है।

खोल केवल एक प्रक्रिया है जो लाइन के दूसरे छोर पर बैठती है, और इसे आपके से stdin प्राप्त करती है टर्मिनल ड्राइवर (जैसे/dev/ttyX) के माध्यम से टर्मिनल, और यह stdout (और stderr) भी एक ही tty से जुड़ा हुआ है।

ध्यान दें कि (यदि गूंज एन है abled) टर्मिनल दोनों प्रक्रिया (समूह) और टर्मिनल पर वापस कीस्ट्रोक भेजता है। Stty कमांड "नियंत्रण" tty प्रक्रियाओं के लिए tty ड्राइवर के लिए ioctl() एस के आसपास सिर्फ रैपर है।

अद्यतन: यह दिखाने के लिए कि खोल शामिल नहीं है, मैंने निम्नलिखित छोटे कार्यक्रम को बनाया है। इसे exec ./a.out के माध्यम से अपने मूल खोल द्वारा निष्पादित किया जाना चाहिए (यह एक इंटरैक्टिव शैल एक बेटी खोल को फोर्क करेगा, वैसे भी) प्रोग्राम उस कुंजी को सेट करता है जो SIGINTR को^बी, स्विच इको बंद करता है, और stdin से इनपुट के लिए इंतजार करता है।

#include <stdio.h> 
#include <string.h> 
#include <termios.h> 
#include <unistd.h> 
#include <signal.h> 
#include <errno.h> 

int thesignum = 0; 
void handler(int signum); 

void handler(int signum) 
{ thesignum = signum;} 

#define THE_KEY 2 /* ^B */ 

int main(void) 
{ 
int rc; 
struct termios mytermios; 

rc = tcgetattr(0 , &mytermios); 
printf("tcgetattr=%d\n", rc); 

mytermios.c_cc[VINTR] = THE_KEY; /* set intr to ^B */ 
mytermios.c_lflag &= ~ECHO ; /* Dont echo */ 
rc = tcsetattr(0 , TCSANOW, &mytermios); 
printf("tcsetattr(intr,%d) =%d\n", THE_KEY, rc); 

printf("Setting handler()\n"); 
signal(SIGINT, handler); 

printf("entering pause()\n... type something followed by ^%c\n", '@'+THE_KEY); 
rc = pause(); 
printf("Rc=%d: %d(%s), signum=%d\n", rc, errno , strerror(errno), thesignum); 

// mytermios.c_cc[VINTR] = 3; /* reset intr to ^C */ 
mytermios.c_lflag |= ECHO ; /* Do echo */ 
rc = tcsetattr(0 , TCSANOW, &mytermios); 
printf("tcsetattr(intr,%d) =%d\n", THE_KEY, rc); 

return 0; 
} 

intr.sh:

#!/bin/sh 
echo $$ 
exec ./a.out 
echo I am back. 
+0

मजेदार बात यह है कि दूसरा उत्तर (जो सादा गलत है) अभी भी अपवॉट हो जाता है, क्योंकि इसमें सही पुस्तकें के लिंक शामिल हैं। – wildplasser

+1

@WiSaGaN वही उत्तर "लगभग सही" (मुझे टिप्पणी करें) और "सादा गलत" (ओपी को टिप्पणी) कैसे हो सकता है। ** बेशक ** परिधीय के माध्यम से सिस्टम के साथ संचार करते समय डिवाइस ड्राइवर शामिल होते हैं (आप कीबोर्ड ड्राइवर का उल्लेख कैसे नहीं करते?) अधिक जानकारी प्रदान करने से "लगभग सही" उत्तर "सादा गलत" नहीं होता है। अगर मैं मशीन भाषा और लुकअप टेबल के स्तर पर गया, तो क्या यह आपके उत्तर को गलत बना देगा? मुश्किल से। मैंने पुस्तकों के लिंक प्रदान किए ताकि ओपी आवश्यकतानुसार अधिक विवरण देख सके। ओपी महसूस किया कि मेरा जवाब सहायक था। आपकी वर्तमान टिप्पणी सबसे अच्छा विरोधाभासी और अपमानजनक है। – Levon

+0

गलत बात यह है कि * खोल शामिल नहीं है *।^सी से आईएनटीआर का रूपांतरण टर्मिनल ड्राइवर में होता है। खोल केवल एक रिसेप्टर है (किसी भी अन्य प्रक्रिया की तरह) stty शैल को लक्षित नहीं कर रहा है, लेकिन tty। – wildplasser

6

शैल आपके द्वारा लिखे गए सब कुछ को छूता है, इसलिए जब आप ^C टाइप करते हैं, तो वह भी प्रतिबिंबित हो जाता है (और आपके मामले में आपके सिग्नल हैंडलर द्वारा अवरुद्ध)। stty -echo कमांड आपकी आवश्यकताओं/बाधाओं के आधार पर आपके लिए उपयोगी हो सकता है या नहीं, अधिक जानकारी के लिए man page for stty देखें।

बेशक

भी बहुत कुछ एक निचले स्तर पर चला जाता है, कभी भी आप इस तरह के कीबोर्ड ड्राइवर है कि आप^सी संकेत उत्पन्न करने के लिए उपयोग करते हैं, और सब कुछ को प्रदर्शित करता है कि टर्मिनल चालक के रूप में (के माध्यम से बाह्य उपकरणों डिवाइस ड्राइवर को एक प्रणाली के साथ संवाद) लिप्त हैं। आप असेंबली/मशीन भाषा, रजिस्टर्स, लुकअप टेबल आदि के स्तर पर भी गहराई से खोद सकते हैं। यदि आप नीचे दी गई पुस्तकों को समझने के लिए एक विस्तृत, गहन स्तर चाहते हैं तो शुरू करने के लिए एक अच्छी जगह है:

The Design of the Unix OS एक है इस तरह की चीजों के लिए अच्छा संदर्भ। दो और क्लासिक संदर्भ:

  • खोल कांटा ही
  • : Unix Programming Environment और Advanced Programming in the UNIX Environment

    इस में अच्छा सारांश यहाँ अतः How does Ctrl-C terminate a child process?

    सवाल "जब आप एक प्रोग्राम है, खोल चलाने के लिए, उदाहरण के लिए find

  • और बच्चे के लिए डिफॉल्ट सिग्नल हैंडलिंग
  • दिए गए आदेश के साथ बच्चे को प्रतिस्थापित करें (उदाहरण के लिए फिन के साथ डी)
  • जब आप CTRL-C दबाते हैं, तो पैरेंट खोल इस सिग्नल को संभालता है लेकिन बच्चा इसे प्राप्त करेगा - डिफ़ॉल्ट क्रिया के साथ - समाप्त हो जाएगा। (बच्चे संकेत हैंडलिंग भी लागू कर सकते हैं) "
+0

तुम्हारा मतलब है कि पार्टी यहाँ है, साथ ही अग्रभूमि प्रक्रिया समूह में है तो यह संकेत गिरी द्वारा भेजे प्राप्त? – WiSaGaN

+1

@WiSaGaN मेरा मतलब है कि आप अपने प्रोग्राम के साथ संवाद करने के लिए कीबोर्ड का उपयोग करते हैं, और खोल आपके और प्रोग्राम (यानी, * इंटरफेस *) के बीच है, इसलिए यह इस क्रिया को रोकता है। आपका सिग्नल हैंडलर क्या करता है * बाद में * क्रिया को निर्धारित करता है जो '^ सी' के बाद होता है। तो कार्यक्रम को समाप्त करने के बजाय, आप इसे कुछ और कर सकते हैं, जैसे कि आपके मामले में एक संदेश प्रिंट करें। – Levon

+0

तो यह वास्तव में शोर भेजना अग्रभूमि प्रक्रिया समूह (कर्नेल वास्तव में इसे लागू करता है) को भेज रहा है। और इसलिए अंतर्निहित घटनाएं हैं, कीबोर्ड ने Ctrl + C दबाया और CPU को सिग्नल किया। फिर एक हार्डवेयर बाधा ने इंटरप्ट हैंडलर को आह्वान किया, जो शेल Ctrl + C दबाता है। फिर खोल द्वारा एक संकेत भेजा जाता है। तो "SIGINT सिग्नल" रूपांतरण के लिए "Ctrl + C कीस्ट्रोक" खोल शैल द्वारा बनाई गई है। क्या मैं सही हूँ? – WiSaGaN

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

  • कोई संबंधित समस्या नहीं^_^