Signaali
Signaali on tapahtuma, joka luodaan ilmoittamaan prosessille tai säikeelle, että jokin tärkeä tilanne on saapunut. Kun prosessi tai säie on vastaanottanut signaalin, prosessi tai säie lopettaa toimintansa ja ryhtyy toimiin. Signaali voi olla hyödyllinen prosessien välisessä viestinnässä.
Vakiosignaalit
Signaalit määritellään otsikkotiedostossa signaali. h makrovakiona. Signaalin nimi on alkanut SIG: llä ja sen jälkeen lyhyt kuvaus signaalista. Joten jokaisella signaalilla on ainutlaatuinen numeerinen arvo. Ohjelmasi tulee aina käyttää signaalien nimeä, ei signaalien numeroa. Syy on signaalin numero voi vaihdella järjestelmän mukaan, mutta nimien merkitys on vakio.
Makro NSIG on määritettyjen signaalien kokonaismäärä. Arvo NSIG on yksi suurempi kuin määritetty signaalien kokonaismäärä (kaikki signaalin numerot varataan peräkkäin).
Seuraavat ovat vakiosignaaleja:
Signaalin nimi | Kuvaus |
SIGHUP | Katkaise prosessi. SIGHUP -signaalia käytetään ilmoittamaan käyttäjän päätelaitteen katkeamisesta, mahdollisesti siksi, että etäyhteys katkeaa tai katkeaa. |
MERKKI | Keskeytä prosessi. Kun käyttäjä kirjoittaa INTR -merkin (yleensä Ctrl + C), SIGINT -signaali lähetetään. |
SIGQUIT | Lopeta prosessi. Kun käyttäjä kirjoittaa QUIT -merkin (yleensä Ctrl + ), SIGQUIT -signaali lähetetään. |
TIIVISTE | Laiton ohje. Kun yritetään suorittaa roskaa tai etuoikeutettua käskyä, SIGILL -signaali luodaan. SIGILL voidaan myös luoda, kun pino ylittää tai kun järjestelmällä on ongelmia signaalinkäsittelijän kanssa. |
SIGTRAP | Jäljitysloukku. Katkaisupiste- ja muut ansautuskäskyt muodostavat SIGTRAP -signaalin. Virheenkorjaaja käyttää tätä signaalia. |
SIGABRT | Keskeyttää. SIGABRT -signaali syntyy, kun keskeytys () -toiminto kutsutaan. Tämä signaali ilmaisee virheen, jonka ohjelma itse havaitsee ja jonka ilmoittaa keskeytystoiminto (). |
SIGFPE | Liukuluku poikkeus. Kun kohtalokas aritmeettinen virhe tapahtui, SIGFPE -signaali luodaan. |
SIGUSR1 ja SIGUSR2 | Signaaleja SIGUSR1 ja SIGUSR2 voidaan käyttää haluamallasi tavalla. On hyödyllistä kirjoittaa heille signaalinkäsittelijä ohjelmaan, joka vastaanottaa signaalin yksinkertaiseen prosessien väliseen viestintään. |
Signaalien oletustoiminto
Jokaisella signaalilla on oletustoiminto, jokin seuraavista:
Termi: Prosessi päättyy.
Ydin: Prosessi päättyy ja tuottaa ydintiedoston.
Ign: Prosessi jättää signaalin huomiotta.
Lopettaa: Prosessi pysähtyy.
Tili: Prosessia jatketaan pysäyttämisestä.
Oletustoimintoa voidaan muuttaa käsittelijätoiminnon avulla. Joidenkin signaalien oletustoimintoja ei voi muuttaa. SIGKILL ja SIGABRT signaalin oletustoimintoa ei voi muuttaa tai jättää huomiotta.
Signaalin käsittely
Jos prosessi vastaanottaa signaalin, prosessi voi valita toiminnon tällaiselle signaalille. Prosessi voi jättää signaalin huomiotta, määrittää käsittelytoiminnon tai hyväksyä oletustoiminnon tällaiselle signaalille.
- Jos signaalin määritetty toiminto jätetään huomiotta, signaali hylätään välittömästi.
- Ohjelma voi rekisteröidä käsittelijätoiminnon käyttämällä toimintoa, kuten signaali tai liioittelu . Tätä kutsutaan käsittelijäksi, joka ottaa signaalin.
- Jos signaalia ei ole käsitelty tai ohitettu, sen oletustoiminto suoritetaan.
Voimme käsitellä signaalia käyttämällä signaali tai liioittelu toiminto. Tässä näemme kuinka yksinkertaisin signaali () -toimintoa käytetään signaalien käsittelyyn.
intsignaali() (intmerkki, mitätön (*toiminto)(int))The signaali () soittaa toiminto toiminto, jos prosessi vastaanottaa signaalin merkki . The signaali () palauttaa osoittimen toimintoon toiminto jos se onnistuu tai palauttaa virheen errno ja -1 muutoin.
The toiminto Osoittimella voi olla kolme arvoa:
- SIG_DFL : Se on osoitus järjestelmän oletustoiminnolle SIG_DFL () , julisti vuonna h otsikkotiedosto. Sitä käytetään signaalin oletustoimintojen suorittamiseen.
- SIG_IGN : Se on osoitus järjestelmän ohitustoiminnolle SIG_IGN () , julisti vuonna h otsikkotiedosto.
- Käyttäjän määrittämä käsittelijätoiminto -osoitin : Käyttäjän määrittämä käsittelijätoimintotyyppi on mitätön (*) (int) , tarkoittaa, että palautustyyppi on mitätön ja yksi argumentin tyyppi int.
Signaalin käsittelijän perusesimerkki
#sisältää#sisältää
#sisältää
mitätönsig_handler(intmerkki){
// Käsittelytoiminnon palautustyypin tulee olla mitätön
printf ('' nSisäkäsittelytoiminto n'');
}
inttärkein(){
signaali(MERKKI,sig_handler); // Rekisteröi signaalinkäsittelijä
varten(inti=1;;i++){ // Ääretön silmukka
printf ('%d: Päätoiminnon sisällä n'',i);
nukkua(1); // Viive 1 sekunti
}
palata 0;
}
Esimerkki 1.c: n tuloksen kuvakaappauksessa voimme nähdä, että päätoiminnossa ääretön silmukka suoritetaan. Kun käyttäjä kirjoittaa näppäinyhdistelmää Ctrl+C, päätoiminnon suoritus pysähtyy ja signaalin käsittelijätoiminto käynnistetään. Käsittelytoiminnon suorittamisen jälkeen päätoiminnon suorittaminen jatkui. Kun käyttäjätyyppi kirjoitti Ctrl+, prosessi lopetetaan.
Esimerkki ohita signaalit
#sisältää#sisältää
#sisältää
inttärkein(){
signaali(MERKKI,SIG_IGN); // Rekisteröi signaalinkäsittelijä signaalin huomiotta jättämiseksi
varten(inti=1;;i++){ // Ääretön silmukka
printf ('%d: Päätoiminnon sisällä n'',i);
nukkua(1); // Viive 1 sekunti
}
palata 0;
}
Tässä käsittelijätoiminto on rekisteröityminen SIG_IGN () toiminto, joka ohittaa signaalitoiminnon. Joten kun käyttäjä kirjoitti Ctrl+C, MERKKI signaali tuottaa, mutta toiminto jätetään huomiotta.
Esimerkki uudelleen rekisteröidystä signaalinkäsittelijästä
#sisältää#sisältää
#sisältää
mitätönsig_handler(intmerkki){
printf ('' nSisäkäsittelytoiminto n'');
signaali(MERKKI,SIG_DFL); // Rekisteröi signaalinkäsittelijä uudelleen oletustoimintoa varten
}
inttärkein(){
signaali(MERKKI,sig_handler); // Rekisteröi signaalinkäsittelijä
varten(inti=1;;i++){ // Ääretön silmukka
printf ('%d: Päätoiminnon sisällä n'',i);
nukkua(1); // Viive 1 sekunti
}
palata 0;
}
Esimerkki3.c: n tuloksen kuvakaappauksessa voimme nähdä, että kun käyttäjä kirjoitti ensimmäisen kerran Ctrl+C, käsittelijätoiminto käynnistyi. Käsittelytoiminnossa signaalinkäsittelijä rekisteröi uudelleen osoitteeseen SIG_DFL signaalin oletustoimintoa varten. Kun käyttäjä kirjoitti Ctrl+C toisen kerran, prosessi lopetetaan, mikä on oletustoiminto MERKKI signaali.
Signaalien lähettäminen:
Prosessi voi myös lähettää nimenomaisesti signaaleja itselleen tai toiselle prosessille. kohota () ja tappaa () -toimintoa voidaan käyttää signaalien lähettämiseen. Molemmat toiminnot ilmoitetaan signal.h -otsikkotiedostossa.
int nostaa (intmerkki)Korotus () -toiminto, jota käytetään signaalin lähettämiseen merkki soittoprosessiin (itse). Se palauttaa nollan, jos onnistuu, ja nollasta poikkeavan arvon, jos se epäonnistuu.
inttappaa(pid_t pid, intmerkki)Kill -toiminto, jota käytetään signaalin lähettämiseen merkki määrittämälle prosessille tai prosessiryhmälle pid .
Esimerkki SIGUSR1 -signaalinkäsittelijästä
#sisältää#sisältää
mitätönsig_handler(intmerkki){
printf ('Sisäkäsittelytoiminto n'');
}
inttärkein(){
signaali(SIGUSR1,sig_handler); // Rekisteröi signaalinkäsittelijä
printf ('Sisäinen päätoiminto n'');
nostaa (SIGUSR1);
printf ('Sisäinen päätoiminto n'');
palata 0;
}
Tässä prosessi lähettää SIGUSR1 -signaalin itselleen käyttämällä lift () -toimintoa.
Nosta tappaesimerkillä
#sisältää#sisältää
#sisältää
mitätönsig_handler(intmerkki){
printf ('Sisäkäsittelytoiminto n'');
}
inttärkein(){
pid_t pid;
signaali(SIGUSR1,sig_handler); // Rekisteröi signaalinkäsittelijä
printf ('Sisäinen päätoiminto n'');
pid=hölmö(); // Prosessin tunnus itsestään
tappaa(pid,SIGUSR1); // Lähetä SIGUSR1 itselleen
printf ('Sisäinen päätoiminto n'');
palata 0;
}
Tässä prosessi lähettää SIGUSR1 signaali itselleen tappaa() toiminto. hullu () käytetään itsensä prosessitunnuksen hankkimiseen.
Seuraavassa esimerkissä näemme, kuinka vanhemman ja lapsen prosessit kommunikoivat (prosessien välinen viestintä) käyttäen tappaa() ja signaalitoiminto.
Vanhemman ja lapsen kommunikointi signaalien kanssa
#sisältää#sisältää
#sisältää
#sisältää
mitätönsig_handler_parent(intmerkki){
printf ('Vanhempi: Vastaanotti lapselta vastaussignaalin n'');
}
mitätönsig_handler_child(intmerkki){
printf ('Lapsi: Signaali vanhemmalta n'');
nukkua(1);
tappaa(kiihkeä(),SIGUSR1);
}
inttärkein(){
pid_t pid;
jos((pid=haarukka())<0){
printf ('Haarukka epäonnistui n'');
poistua (1);
}
/ * Lapsiprosessi */
muu jos(pid==0){
signaali(SIGUSR1,sig_handler_child); // Rekisteröi signaalinkäsittelijä
printf ('Lapsi: odottaa signaalia n'');
tauko();
}
/ * Vanhemman prosessi */
muu{
signaali(SIGUSR1,sig_handler_parent); // Rekisteröi signaalinkäsittelijä
nukkua(1);
printf ('Vanhempi: lähettää signaalia lapselle n'');
tappaa(pid,SIGUSR1);
printf ('Vanhempi: vastausta odotellessa n'');
tauko();
}
palata 0;
}
Tässä, haarukka() toiminto luo aliprosessin ja palauttaa nolla aliprosessille ja aliprosessin tunnuksen vanhemman prosessille. Joten pid on tarkistettu päättämään vanhemman ja lapsen prosessista. Vanhempainprosessissa se nukkuu 1 sekunnin ajan, jotta lapsiprosessi voi rekisteröidä signaalinkäsittelytoiminnon ja odottaa vanhemman signaalia. Lähetä yhden toisen vanhemman prosessin jälkeen SIGUSR1 signaali lapselle prosessi ja odota vastaussignaalia lapselta. Lapsiprosessissa se odottaa ensin vanhempien signaalia ja kun signaali vastaanotetaan, ohjaustoimintoa käytetään. Käsittelytoiminnosta aliprosessi lähettää toisen SIGUSR1 signaali vanhemmalle. Tässä getppid () -toimintoa käytetään vanhemman prosessitunnuksen saamiseen.
Johtopäätös
Signaali Linuxissa on suuri aihe. Tässä artikkelissa olemme nähneet kuinka käsitellä signaalia aivan perusasioista ja saada myös tietoa siitä, miten signaali syntyy, kuinka prosessi voi lähettää signaalin itselleen ja muulle prosessille, kuinka signaalia voidaan käyttää prosessien välisessä viestinnässä.