C Програмиране

Как да използвам манипулаторите на сигнал на език C?

Как да използвам манипулаторите на сигнал на език C?
В тази статия ще ви покажем как да използвате манипулаторите на сигнали в Linux, използвайки езика C. Но първо ще обсъдим какво е сигнал, как ще генерира някои често срещани сигнали, които можете да използвате във вашата програма и след това ще разгледаме как различни сигнали могат да бъдат обработвани от програма, докато програмата изпълнява. И така, да започнем.

Сигнал

Сигналът е събитие, което се генерира, за да уведоми процес или нишка, че е настъпила някаква важна ситуация. Когато даден процес или нишка получи сигнал, процесът или нишката ще спре това, което прави и ще предприеме някакви действия. Сигналът може да бъде полезен за комуникация между процесите.

Стандартни сигнали

Сигналите са дефинирани в заглавния файл сигнал.з като макроконстанта. Името на сигнала е започнало със „SIG“ и последвано от кратко описание на сигнала. И така, всеки сигнал има уникална числова стойност. Вашата програма винаги трябва да използва името на сигналите, а не номера на сигналите. Причината е, че номерът на сигнала може да се различава според системата, но значението на имената ще бъде стандартно.

Макросът NSIG е общият брой на дефинирания сигнал. Стойността на NSIG е по-голям от общия брой на дефинирания сигнал (Всички номера на сигнала се разпределят последователно).

Следват стандартните сигнали:

Име на сигнала Описание
ВДИХАНЕ Затворете процеса. Сигналът SIGHUP се използва за докладване на прекъсване на връзката на потребителя, вероятно защото дистанционната връзка е загубена или прекъсва.
ЗНАЧЕНИЕ Прекъснете процеса. Когато потребителят напише знака INTR (обикновено Ctrl + C), сигналът SIGINT се изпраща.
SIGQUIT Затворете процеса. Когато потребителят напише символа QUIT (обикновено Ctrl + \), се изпраща сигнал SIGQUIT.
SIGILL Незаконни инструкции. Когато се прави опит за изпълнение на боклук или привилегирована инструкция, се генерира сигнал SIGILL. Също така, SIGILL може да се генерира, когато стекът прелива или когато системата има проблеми с работата на обработващ сигнал.
SIGTRAP Трасиращ капан. Инструкция за точка на прекъсване и друга инструкция за улавяне ще генерират сигнала SIGTRAP. Дебъгерът използва този сигнал.
SIGABRT Прекъсване. Сигналът SIGABRT се генерира при извикване на функцията abort (). Този сигнал показва грешка, която се открива от самата програма и се съобщава от извикването на функцията abort ().
SIGFPE Изключение с плаваща запетая. Когато възникне фатална аритметична грешка, генерира се сигнал SIGFPE.
SIGUSR1 и SIGUSR2 Сигналите SIGUSR1 и SIGUSR2 могат да се използват както желаете. Полезно е да се напише обработващ сигнал за тях в програмата, която получава сигнала за проста комуникация между процесите.

Действие по подразбиране на сигналите

Всеки сигнал има действие по подразбиране, едно от следните:

Срок: Процесът ще приключи.
Ядро: Процесът ще прекрати и ще създаде основен файл за изхвърляне.
Ign: Процесът ще игнорира сигнала.
Спри се: Процесът ще спре.
Напред: Процесът ще продължи от спиране.

Действието по подразбиране може да бъде променено с помощта на функцията манипулатор. Действието по подразбиране на някои сигнали не може да бъде променено. SIGKILL и SIGABRT действието по подразбиране на сигнала не може да бъде променено или пренебрегнато.

Обработка на сигнала

Ако процесът получи сигнал, процесът има избор на действие за този вид сигнал. Процесът може да игнорира сигнала, може да посочи функция манипулатор или да приеме действието по подразбиране за този вид сигнал.

Можем да се справим със сигнала, използвайки сигнал или сигакция функция. Тук виждаме как е най-просто сигнал () функцията се използва за обработка на сигнали.

int signal () (int signum, void (* func) (int))

The сигнал () ще се обади на func функция, ако процесът получи сигнал signum. The сигнал () връща указател към функция func ако е успешно или връща грешка на errno и -1 в противен случай.

The func указателят може да има три стойности:

  1. SIG_DFL: Това е указател към функцията по подразбиране на системата SIG_DFL (), деклариран през з заглавен файл. Използва се за действие по подразбиране на сигнала.
  2. SIG_IGN: Това е указател към функцията за игнориране на системата SIG_IGN (),деклариран в з заглавен файл.
  3. Потребителски указател за функция на манипулатора: Дефинираният от потребителя тип функция на манипулатора е void (*) (int), означава връщане тип е void и един аргумент от тип int.

Пример за основен манипулатор на сигнали

#include
#include
#include
void sig_handler (int signum)
// Типът връщане на функцията манипулатор трябва да бъде void
printf ("\ nВътрешна функция на манипулатора \ n");

int main ()
сигнал (SIGINT, sig_handler); // Регистрирайте манипулатора на сигнала
for (int i = 1 ;; i ++) // Безкраен цикъл
printf ("% d: Вътре в основната функция \ n", i);
сън (1); // Забавяне за 1 секунда

връщане 0;

На екранната снимка на изхода на Example1.c, можем да видим, че в основната функция се изпълнява безкраен цикъл. Когато потребителят въведе Ctrl + C, изпълнението на основната функция спира и се извиква функцията манипулатор на сигнала. След завършване на функцията манипулатор, изпълнението на основната функция е възобновено. Когато потребител въведе Ctrl + \, процесът се прекратява.

Пример за игнориране на сигнали

#include
#include
#include
int main ()
сигнал (SIGINT, SIG_IGN); // Регистрирайте манипулатора на сигнал за игнориране на сигнала
for (int i = 1 ;; i ++) // Безкраен цикъл
printf ("% d: Вътре в основната функция \ n", i);
сън (1); // Забавяне за 1 секунда

връщане 0;

Тук функцията за обработване е регистрирана в SIG_IGN () функция за игнориране на сигналното действие. Така че, когато потребителят въведе Ctrl + C,  ЗНАЧЕНИЕ сигнал се генерира, но действието се игнорира.

Пререгистрирайте пример за обработване на сигнали

#include
#include
#include
void sig_handler (int signum)
printf ("\ nВътрешна функция на манипулатора \ n");
сигнал (SIGINT, SIG_DFL); // Регистрирайте манипулатора на сигнала за действие по подразбиране

int main ()
сигнал (SIGINT, sig_handler); // Регистрирайте манипулатора на сигнала
for (int i = 1 ;; i ++) // Безкраен цикъл
printf ("% d: Вътре в основната функция \ n", i);
сън (1); // Забавяне за 1 секунда

връщане 0;

На екранната снимка на резултата от Example3.c, можем да видим, че когато потребителят за първи път въведе Ctrl + C, се извиква функцията манипулатор. Във функцията манипулатор манипулаторът на сигнал се регистрира отново SIG_DFL за действие по подразбиране на сигнала. Когато потребителят въведе Ctrl + C за втори път, процесът се прекратява, което е действието по подразбиране на ЗНАЧЕНИЕ сигнал.

Изпращане на сигнали:

Процесът също може изрично да изпраща сигнали към себе си или към друг процес. Функцията рейз () и убийство () може да се използва за изпращане на сигнали. И двете функции са декларирани в сигнал.h заглавен файл.

инт рейз (int signum)

Функцията рейз (), използвана за изпращане на сигнал signum към процеса на извикване (себе си). Връща нула, ако е успешна, и ненулева стойност, ако не успее.

int kill (pid_t pid, int signum)

Функцията за убиване, използвана за изпращане на сигнал signum към процес или група процеси, посочени от pid.

Пример за обработване на сигнали SIGUSR1

#include
#include
void sig_handler (int signum)
printf ("Функция за вътрешен манипулатор \ n");

int main ()
сигнал (SIGUSR1, sig_handler); // Регистрирайте манипулатора на сигнала
printf ("Вътре в основната функция \ n");
рейз (SIGUSR1);
printf ("Вътре в основната функция \ n");
връщане 0;

Тук процесът изпраща сигнал SIGUSR1 към себе си, използвайки функцията рейз ().

Повишаване с програма за убиване на примери

#include
#include
#include
void sig_handler (int signum)
printf ("Функция за вътрешен манипулатор \ n");

int main ()
pid_t pid;
сигнал (SIGUSR1, sig_handler); // Регистрирайте манипулатора на сигнала
printf ("Вътре в основната функция \ n");
pid = getpid (); // Идентификатор на процеса на себе си
убийство (pid, SIGUSR1); // Изпратете SIGUSR1 до себе си
printf ("Вътре в основната функция \ n");
връщане 0;

Тук процесът се изпраща SIGUSR1 сигнал към себе си, използвайки kill () функция. getpid () се използва за получаване на идентификатора на процеса на себе си.

В следващия пример ще видим как родителите и децата обработват комуникации (Inter Process Communication) с помощта kill () и сигнална функция.

Комуникация на родителско дете със сигнали

#include
#include
#include
#include
void sig_handler_parent (int signum)
printf ("Родител: Получи сигнал за отговор от дете \ n");

void sig_handler_child (int signum)
printf ("Дете: Получи сигнал от родител \ n");
сън (1);
kill (getppid (), SIGUSR1);

int main ()
pid_t pid;
if ((pid = fork ())<0)
printf ("Fork Failed \ n");
изход (1);

/ * Детски процес * /
иначе ако (pid == 0)
сигнал (SIGUSR1, sig_handler_child); // Регистрирайте манипулатора на сигнала
printf ("Дете: чака сигнал \ n");
пауза ();

/ * Родителски процес * /
друго
сигнал (SIGUSR1, sig_handler_parent); // Регистрирайте манипулатора на сигнала
сън (1);
printf ("Родител: изпращане на сигнал към дете \ n");
убийство (pid, SIGUSR1);
printf ("Родител: чака отговор \ n");
пауза ();

връщане 0;

Тук, вилица () функция създава дъщерен процес и връща нула на дъщерния процес и идентификатор на дъщерния процес на родителския процес. И така, pid е проверен, за да реши процеса родител и дете. В родителския процес той се изключва за 1 секунда, за да може дъщерният процес да регистрира функцията за обработка на сигнали и да изчака сигнала от родителя. След 1 секунда родителски процес изпратете SIGUSR1 сигнал към дете процес и изчакайте сигнала за отговор от дете. В дъщерния процес първо се изчаква сигнал от родител и когато се получи сигнал, се извиква функция манипулатор. От функцията манипулатор дъщерният процес изпраща друг SIGUSR1 сигнал на родител. Тук getppid () функцията се използва за получаване на идентификатор на родителски процес.

Заключение

Сигналът в Linux е голяма тема. В тази статия видяхме как да боравим със сигнала от самото основно, а също така получихме знания как генерира сигнала, как процесът може да изпрати сигнал към себе си и други процеси, как сигналът може да се използва за комуникация между процесите.

Добавете жестове на мишката към Windows 10, като използвате тези безплатни инструменти
През последните години компютрите и операционните системи значително се развиха. Имаше време, когато потребителите трябваше да използват команди за на...
Контролирайте и управлявайте движението на мишката между множество монитори в Windows 10
Двоен дисплей на мишката ви позволява да контролирате и конфигурирате движението на мишката между множество монитори, като забавя движенията му близо ...
WinMouse ви позволява да персонализирате и подобрите движението на показалеца на мишката на компютър с Windows
Ако искате да подобрите функциите по подразбиране на показалеца на мишката, използвайте безплатна програма WinMouse. Той добавя още функции, за да ви ...