моя контактная информация
Почтамезофия@protonmail.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Сигнал (signal) — это программное прерывание. Это метод передачи сообщений между процессами. Он используется для уведомления процесса о том, что произошло событие, но не может передать процессу какие-либо данные.
Существует множество причин, по которым генерируются сигналы. В Shell вы можете использовать.kill
иkillall
Команда для отправки сигнала:
kill -信号的类型 进程编号
killall -信号的类型 进程名
название сигнала | значение сигнала | Действие обработки по умолчанию | Причина подачи сигнала |
---|---|---|---|
ПОДПИШИТЕСЬ | 1 | А | Терминал зависает или процесс управления завершается |
SIGINT | 2 | А | Прерывание клавиатуры Ctrl+c |
СИГКВИТ | 3 | С | Нажата клавиша Escape на клавиатуре |
СИГИЛЛ | 4 | С | Незаконное указание |
СИГТРАП | 5 | С | инструкции точки останова |
СИГАБРТ | 6 | С | Сигнал прерывания, выданный abort(3) |
СИГБУС | 7 | С | ошибка шины |
СИГФПЭ | 8 | С | исключение с плавающей запятой |
SIGKILL | 9 | А | kill -9 убивает процесс, этот сигнал нельзя перехватить и игнорировать |
SIGUSR1 | 10 | А | Определяемый пользователем сигнал 1 |
СИГСЭГВ | 11 | С | Неверная ссылка на память (массив выходит за пределы, операция с нулевым указателем) |
SIGUSR2 | 12 | А | Определяемый пользователем сигнал 2 |
СИГПАЙП | 13 | А | Запись данных в канал без процесса чтения |
СИГАЛРМ | 14 | А | Сигнал будильника, сигнал, отправленный функцией Alarm() |
СИГТЕРМ | 15 | А | Сигнал завершения, сигнал, отправленный по умолчанию |
SIGSTKFLT | 16 | А | ошибка стека |
СИГЧЛД | 17 | Б | Генерируется, когда дочерний процесс завершается |
SIGCONT | 18 | Д | Возобновить остановленный процесс |
СИГНАЛ СТОП | 19 | Д | Остановить процесс |
SIGTSTP | 20 | Д | Нажмите кнопку остановки терминала |
СИГТТИН | 21 | Д | Запросы фонового процесса на чтение терминала |
СИГТТОУ | 22 | Д | Фоновый процесс запрашивает запись на терминал |
СИГУРГ | 23 | Б | Обнаружение аварийного состояния (розетка) |
SIGXCPU | 24 | С | Превышен лимит процессорного времени |
SIGXFSZ | 25 | С | Превышен лимит размера файла |
SIGVTALRM | 26 | А | виртуальный тактовый сигнал |
СИГПРОФ | 27 | А | Анализ тактовых сигналов |
СИГВИНЧ | 28 | Б | Изменение размера окна |
СИГПОЛЛ | 29 | Б | Опрос (Sys V) |
SIGPWR | 30 | А | сбой в электричестве |
СИГСИС | 31 | С | Незаконный системный вызов |
Действием по умолчанию для A является завершение процесса.
По умолчанию действие B — игнорировать этот сигнал.
По умолчанию действие C — завершить процесс и создать дамп образа ядра.
Действием D по умолчанию является остановка процесса, и программа, перешедшая в состояние остановки, может продолжать выполнение.
Процессы могут обрабатывать сигналы тремя способами:
signal()
Функции могут устанавливать способ обработки сигналов программой.
Объявление функции:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Описание параметра:
sig
:Укажите сигнал для захвата.func
: Указатель на функцию обработки сигнала. Функция обработки должна получить целочисленный параметр, который представляет собой номер захваченного сигнала.SIG_DFL
Макрос :SIG_DFL представляет метод обработки сигнала по умолчанию.использоватьSIG_DFL
какsignal
Второй параметр функции указывает, что для сигнала используется системный метод обработки по умолчанию.SIG_IGN
Макрос :SIG_IGN означает игнорирование сигнала.использоватьSIG_IGN
какsignal
Второй параметр функции указывает, что когда процесс получит сигнал, он проигнорирует его и не будет выполнять никакой обработки. Это может предотвратить неожиданное завершение или прерывание процессов при определенных обстоятельствах.SIG_ERR
:SIG_ERR
Макросы используются для обозначения ошибок.это не такsignal
Вместо этого используется второй параметр функции какsignal
Возвращаемое значение функции указывает на то, что вызов не удался.еслиsignal
Если вызов функции завершится неудачей, она вернетSIG_ERR
.Обычно это используется для обнаружения и обработкиsignal
Ошибка при вызове функции.Сервисная программа работает в фоновом режиме. Если вы хотите остановить ее, убивать ее — не лучшая идея, потому что, когда процесс завершается, он внезапно завершает работу, и никакие последующие действия не выполняются.
Если вы отправите сигнал сервисной программе, после получения сигнала сервисная программа вызывает функцию и записывает в нее код последствия, и программа может завершить работу запланированным образом.
Отправка сигнала 0 сервисной программе позволяет определить, активна ли программа.
Операционная система Linux обеспечивает kill
иkillall
Команда отправляет сигнал программе. В программе можно использовать.kill()
Библиотечные функции отправляют сигналы другим процессам.
Объявление функции:
int kill(pid_t pid, int sig);
kill()
Функция принимает параметрыsig
Указанный сигнал передается в параметрpid
указанный процесс.
параметр pid
Есть несколько ситуаций:
pid > 0
Передайте сигнал процессу какpid
процесс.pid = 0
Передайте сигнал всем процессам в той же группе процессов, что и текущий процесс. Он часто используется родительским процессом для отправки сигналов дочернему процессу. Обратите внимание, что такое поведение зависит от реализации системы.pid < -1
Передайте сигнал идентификатору группы процессов|pid|
всех процессов.pid = -1
Передает сигнал всем процессам, имеющим разрешение на отправку сигнала, но не процессу, отправившему сигнал.Существует 8 способов завершить процесс, 5 из которых являются обычным завершением:
main()
Для функцийreturn
возвращаться;exit()
функция;_exit()
или_Exit()
функция;return
возвращаться;pthread_exit()
возвращаться;Есть три способа аварийного завершения:
abort()
прерывание функции;существовать main()
В функцииreturn
Возвращаемое значение является статусом завершения, если нет.return
заявление или звонокexit()
, то статус завершения процесса равен 0.
В оболочке просмотрите статус завершения процесса:
echo $?
3 функции для нормального завершения процесса (exit()
и_Exit()
определяется ISO C,_exit()
определяется POSIX):
void exit(int status);
void _exit(int status);
void _Exit(int status);
status
Статус завершения процесса.
return
Указывает, что при возврате функции будет вызван деструктор локального объекта.main()
в функцииreturn
Также вызывается деструктор глобального объекта.exit()
Указывает на завершение процесса, деструктор локального объекта вызываться не будет, будет вызываться только деструктор глобального объекта._exit()
и_Exit()
Выйдите напрямую, и никаких работ по очистке выполняться не будет.Процесс доступен atexit()
Регистрация функций завершает функции (до 32), эти функции будутexit()
Автоматически вызывается.
int atexit(void (*function)(void));
exit()
Порядок вызова функций завершения меняется с момента регистрации.
system()
Функция предоставляет простой метод выполнения программы, передавая программу и параметры, которые необходимо выполнить, в виде строки.system()
Просто функционируйте.
Объявление функции:
int system(const char * string);
system()
Возвращаемое значение функции вызывает больше проблем.
system()
Функция возвращает ненулевое значение;system()
Функция возвращает 0;system()
Функция возвращает ненулевое значение.exec
Семейства функций предоставляют еще один способ вызова программ (двоичных файлов или сценариев оболочки) внутри процесса.
exec
Семейство функций объявлено следующим образом:
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
Уведомление:
errno
середина.exec
После этого вызываемая программа заменит вызывающую, то естьexec
Никакой код после функции не будет выполнен.execl()
иexecv()
, другие используются редко.Все процессы во всей системе Linux имеют древовидную структуру.
использоватьpstree
Посмотреть дерево процессов можно командой:
pstree -p 进程编号
Каждый процесс имеет уникальный идентификатор процесса, представленный неотрицательным целым числом. Несмотря на уникальность идентификаторов процессов, их можно использовать повторно. Когда процесс завершается, его идентификатор процесса становится кандидатом на повторное использование. Linux использует алгоритм отложенного повторного использования, поэтому идентификатор вновь созданного процесса отличается от идентификатора, используемого недавно завершенным процессом. Это предотвращает принятие новых процессов за завершенный процесс, использующий тот же идентификатор.
Функция для получения идентификатора процесса:
pid_t getpid(void); // 获取当前进程的ID。
pid_t getppid(void); // 获取父进程的ID。
Существующий процесс может вызватьfork()
Функция создает новый процесс.
Объявление функции:
pid_t fork(void);
Зависит отfork()
Созданный новый процесс называется дочерним процессом.
fork()
Функция вызывается один раз, но возвращает результат дважды. Разница между двумя возвращаемыми значениями заключается в том, что возвращаемое значение дочернего процесса равно 0, а возвращаемое значение родительского процесса — это идентификатор вновь созданного дочернего процесса.
Дочерний процесс и родительский процесс продолжают выполнятьсяfork()
Код после этого, Дочерний процесс является копией родительского процесса. Дочерний процесс имеет копию пространства данных, кучи и стека родительского процесса (примечание: дочерний процесс владеет копией, не используемой совместно с родительским процессом).
fork()
После этого порядок выполнения родительского и дочернего процессов не определен.
fork()
, позвольте дочернему процессу обрабатывать эти запросы, в то время как родительский процесс продолжает ждать следующего запроса на соединение.fork()
Позвонили сразу после возвращенияexec
。fork()
Одна из особенностей заключается в том, что файловые дескрипторы, открытые в родительском процессе, будут скопированы в дочерний процесс, а родительский и дочерний процессы имеют одно и то же файловое смещение.
Если родительский процесс и дочерний процесс записывают данные в файл, на который указывает один и тот же дескриптор, без какой-либо синхронизации, их выходные данные могут быть смешаны друг с другом.
На этом этапе вы можете видеть, что имеется только 100 000 строк данных.
В это время должно быть 200 000 строк данных. Возможно, на одну строку меньше, потому что операция записи файла не является атомарной. В отсутствие механизма синхронизации два процесса могут попытаться записать разные части файла одновременно, что приведет к возникновению ошибки. запись не удалась. Данные мешают друг другу.
vfork()
Вызовы функций и возвращаемые значения такие же, какfork()
То же самое, но их семантика разная.
vfork()
Функция используется для создания нового процесса, целью которого являетсяexec
Новая программа, которая не копирует адресное пространство родительского процесса, поскольку дочерний процесс немедленно вызываетexec
, поэтому адресное пространство родительского процесса не будет использоваться. Если дочерний процесс использует адресное пространство родительского процесса, могут возникнуть неизвестные результаты.
vfork()
иfork()
Еще одно отличие:vfork()
Убедитесь, что дочерний процесс запускается первым, и вызовите его в дочернем процессе.exec
илиexit
Затем родительский процесс возобновляет работу.
В операционной системе процесс-зомби относится к дочернему процессу, который завершился, но его родительский процесс еще не прочитал статус своего завершения. Хотя процесс-зомби больше не выполняется, он по-прежнему занимает запись в таблице процессов, чтобы ядро могло сохранять информацию о статусе завершения процесса (например, идентификатор процесса, статус завершения и т. д.) до тех пор, пока родительский процесс не прочитает эту информацию.
Если родительский процесс завершается раньше дочернего процесса, дочерний процесс будет размещен в процессе 1 (это также способ запустить процесс в фоновом режиме).
Если дочерний процесс завершается раньше родительского процесса и родительский процесс не обрабатывает информацию о выходе дочернего процесса, то дочерний процесс станет процессом-зомби.
Ядро сохраняет структуру данных для каждого дочернего процесса, включая номер процесса, статус завершения, используемое время ЦП и т. д. Если родительский процесс обрабатывает информацию о выходе дочернего процесса, ядро освободит эту структуру данных. Если родительский процесс не обрабатывает информацию о выходе дочернего процесса, ядро не освободит эту структуру данных, и номер дочернего процесса всегда будет занят. Номера процессов, доступные в системе, ограничены. Если генерируется большое количество процессов-зомби, система не сможет генерировать новые процессы, поскольку доступных номеров процессов нет.
signal(SIGCHLD, SIG_IGN)
Сообщите ядру, что оно не заинтересовано в выходе дочернего процесса, и его структура данных будет освобождена сразу после выхода дочернего процесса.wait()
/waitpid()
функция: родительский процесс ожидает завершения дочернего процесса, вызывая эти функции, и получает статус завершения, тем самым освобождая ресурсы, занятые дочерним процессом.pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);
pid_t wait3(int *status, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
Возвращаемое значение — это номер дочернего процесса.
stat_loc
Есть ли информация о завершении дочернего процесса:
а) При нормальном завершении макроса WIFEXITED(stat_loc)
Вернуть истину, макросWEXITSTATUS(stat_loc)
Статус прекращения можно получить;
б) Если он завершается ненормально, макрос WTERMSIG(stat_loc)
Получает сигнал о завершении процесса.
Если родительский процесс занят, вы можете захватить SIGCHLD
Сигнал, вызываемый в функции обработки сигналаwait()
/waitpid()
。
[Отправка сигналов между процессами](##1.5 Отправка сигналов)
В многопроцессной сервисной программе, если подпроцесс получает сигнал выхода, он завершится самостоятельно.
Если родительский процесс получает сигнал выхода, он должен отправить сигналы выхода всем дочерним процессам, а затем завершиться сам.
Многопоточные процессы совместно используют адресное пространство процесса.Если нескольким потокам требуется доступ к одной и той же памяти, просто используйте глобальные переменные.。
В нескольких процессах адресное пространство каждого процесса независимо и не используется совместно.Если нескольким процессам требуется доступ к одной и той же памяти, глобальные переменные использовать нельзя, можно использовать только общую память.。
Общая память позволяет нескольким процессам (кровное родство между процессами не требуется) получать доступ к одному и тому же пространству памяти. Это наиболее эффективный способ совместного использования и передачи данных между несколькими процессами. Процессы могут подключать общую память к своему собственному адресному пространству. Если один процесс изменяет данные в общей памяти, данные, считываемые другими процессами, также изменятся.
Общая память не обеспечивает механизм блокировки, то есть, когда процесс читает/записывает общую память, он не мешает другим процессам читать/записывать ее.Если вы хотите заблокировать чтение/запись общей памяти, вы можете использовать семафор . Linux предоставляет набор функций для работы с общей памятью.
Эта функция используется для создания/получения общей памяти.
int shmget(key_t key, size_t size, int shmflg);
typedef unsigned int key_t
), обычно в шестнадцатеричном формате, например 0x5005
, ключи разных общих воспоминаний не могут быть одинаковыми.0666|IPC_CREAT
Указывает, что если общая память не существует, создайте ее.использовать ipcs -m
Вы можете просмотреть общую память системы, включая: ключ (key), идентификатор общей памяти (shmid), владельца (владелец), разрешения (perms) и размер (в байтах).
использовать ipcrm -m 共享内存id
Общая память может быть удалена вручную следующим образом:
Примечание. Контейнеры нельзя использовать для типов данных в общей памяти, можно использовать только базовые типы данных.
Эта функция используется для подключения общей памяти к адресному пространству текущего процесса.
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmget()
Идентификатор общей памяти, возвращаемый функцией.Возвращает начальный адрес общей памяти в случае успешного вызова и возвращает его в случае сбоя. (void *)-1
。
Эта функция используется для отделения общей памяти от текущего процесса, что эквивалентно shmat()
Обратная операция функции.
int shmdt(const void *shmaddr);
shmat()
Адрес, возвращаемый функцией.Возвращает 0, если вызов успешен, и -1, если он не удался.
Эта функция используется для управления общей памятью. Наиболее часто используемой операцией является удаление общей памяти.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
Идентификатор общей памяти, возвращаемый функцией.IPC_RMID
。Возвращает 0, если вызов успешен, и -1, если он не удался.
Обратите внимание, используйте root
Созданная общая память не может быть удалена обычными пользователями независимо от созданных разрешений.
Возвращает 0, если вызов успешен, и -1, если он не удался.
Эта функция используется для управления общей памятью. Наиболее часто используемой операцией является удаление общей памяти.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
Идентификатор общей памяти, возвращаемый функцией.IPC_RMID
。Возвращает 0, если вызов успешен, и -1, если он не удался.
Обратите внимание, используйте root
Созданная общая память не может быть удалена обычными пользователями независимо от созданных разрешений.
[Изображения по внешней ссылке передаются...(img-v6qW3XRA-1720711279572)]
[Изображения по внешней ссылке передаются...(img-CG0tGAne-1720711279572)]