Continuando com o artigo anterior, este capítulo aprenderá primeiro sobre sinais com parâmetros e funções como sigqueue e sigaction
Desenvolvimento multiplataforma (Linux) baseado em VS2019 C++ (1.4) - Signal
I. Introdução
A função kill que mencionamos no último artigo envia um sinal apenas para um determinado processo e não reflete os parâmetros. Também foi mencionado anteriormente que o compartilhamento de dados não pode ser realizado no processo, mesmo que uma variável global seja definida e modificada entre processos filho, o processo pai não sabe se foi modificado ou não. Portanto, esta situação requer comunicação IPC para resolver, e kill não pode transmitir dados, então você precisa usar um sinal com parâmetros
2. Protótipo de função
1. função da biblioteca sigaction - sinal de ligação
Função: Usada para alterar o comportamento de um processo após receber um sinal específico.
Arquivo de cabeçalho <signal.h>
原型: int sigaction(int signum,const struct sigaction *act,const struct sigaction *old);
parâmetro
- O primeiro parâmetro é o valor do sinal, que pode ser qualquer sinal válido específico, exceto sigkill e sigstop (defina sua própria função de processamento para esses dois sinais, o que resultará em um erro de instalação do sinal)
- O segundo parâmetro é um ponteiro para uma instância da estrutura sigaction. Na instância da estrutura sigaction, o processamento de um sinal específico é especificado. Ele pode estar vazio, e o processo processará o sinal por padrão.
- O objeto apontado pelo terceiro parâmetro oldact é usado para salvar o processamento original do sinal correspondente, geralmente null .
Nota: Os parâmetros dois e três são ponteiros para estruturas. O segundo parâmetro é o mais importante . A função de processamento de sinal está incluída nesta estrutura, mas a função não pode ser atribuída diretamente ao segundo parâmetro quando é usada.
Valor de retorno: A função retorna 0 em caso de sucesso, -1 em caso de falha
Veja a função sigaction no linux da seguinte forma
A estrutura do segundo parâmetro correspondente seguection é a seguinte
Não pode haver uma função na estrutura c, mas aqui apenas o ponteiro de função é reservado, e isso não quebra a estipulação de que não pode haver uma função na estrutura. Para a estrutura, é apenas uma variável de ponteiro (mais especial, apontando para uma função)
A primeira é semelhante ao ponteiro de função sem parâmetros mencionados acima, então usamos a segunda função para implementar o sinal com parâmetros e, em seguida, usamos sa_flags para determinar se ele possui parâmetros
2, função de biblioteca sigqueue - enviar sinal
Função: A nova chamada de sistema para envio de sinais, principalmente para sinais em tempo real, suporta sinais com parâmetros e é usada em pares com a função sigaction().
Valor: int sigqueue(pid_t pid, int sig, const union sigval value);
parâmetro
- O primeiro parâmetro é o id do processo que especifica o sinal de recebimento
- O segundo parâmetro determina o sinal que está prestes a ser enviado
- O terceiro parâmetro é uma estrutura de dados union sigval (semelhante à estrutura, raramente usada), que especifica os parâmetros passados pelo sinal, ou seja, o chamado valor de 4 bytes.
Valor de retorno: 0 para sucesso, -1 para falha
Veja a função sigqueue no linux da seguinte forma
A união sigval correspondente do segundo parâmetro é a seguinte
Onde sigval_int são os dados inteiros a serem enviados
3. Realização
1. Código de exemplo
Este exemplo implementa o processo pai para enviar sinais e passar dados para o processo filho
①O void signalFunc(int i) anterior é adequado apenas para o uso de sinais sem parâmetro, portanto, a função redefinida é a seguinte
void sigaction_func(int num, siginfo_t* info, void* vo)
O primeiro número do parâmetro é o código do sinal recebido e os dados recebidos são armazenados nas informações do segundo parâmetro
② Os dados enviados por sigqueue devem estar na forma de consórcio
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include<iostream>
#include <signal.h>
#include<stdio.h>
#include <stdlib.h>
using namespace std;
//带参数的信号
void sigaction_func(int num, siginfo_t* info, void* vo);
int main(){
int pid = 0;
//准备结构体
struct sigaction act;
act.sa_sigaction = sigaction_func;
act.sa_flags = SA_SIGINFO;//带参数的信号
//绑定信号
sigaction(SIGUSR1,&act,NULL); //发送是sigqueue
pid = fork();
if (pid == 0)
{
while (true)
{
cout << "子进程运行中 ...pid =" << getpid() << endl;
sleep(1);
}
}
else if (pid > 0)
{
sleep(2);
//准备要传递的数据
union sigval value;
value.sival_int = 111;
//带参数发送信号
sigqueue(pid, SIGUSR1, value);//第三个参数跟之前不一样,是一个联合体
//卡住父进程
while (1) {}
}
return 0;
}
void sigaction_func(int num, siginfo_t* info, void* vo)
{
int x = info->si_int;
cout <<"当前进程pid = "<<getpid()<<" sigaction_func函数被调用了,num = " << num << " 信号传递过来的数据是 x = " << x<< endl;
}
2. Resultados em execução
4. Resumo
Os dados passados no exemplo anterior são apenas um inteiro, então algumas pessoas podem notar o segundo parâmetro void * na união sigval (como mostrado abaixo), pensando que ele pode ser usado para implementar outros tipos de dados, mas este não é o caso.
1. Quando os primeiros desenvolvedores desenvolveram os sinais, eles só suportavam a transferência de dados do tipo int, então eles pensaram em reservar um void * para uso posterior, mas infelizmente, a transferência de dados de void * ainda não é suportada na versão ubuntu20, e isso ainda não foi realizado.Atualização, então dados complexos (arrays, estruturas) não podem ser passados, o que é muito insípido.
2. Como o IPC possui cinco métodos de comunicação, não é apenas possível usar sinais para transferir dados entre processos, porque a operação problemática dos sinais torna apenas o uso básico da comunicação
3. Quando o processo filho recebe um sinal desconhecido (por exemplo, altere SIGUSR1 no código acima para SIGUSR2 em sigqueue(pid, SIGUSR1, value);) e a função de ligação não é executada, o resultado em execução é o seguinte, o processo filho não sabe Faça nada e você ficará preso
Compile novamente no linux
Neste ponto, verifique se o estado do processo é Z+ (estado zumbi - o processo filho termina antes do processo pai. Há um loop infinito no processo filho, que não deve terminar primeiro, mas porque o processo filho recebe um sinal desconhecido, será interrompido, o processo filho está preso lá, ou seja, a coisa original não faz e não sabe o que fazer a seguir, entra no estado zumbi, ocupa recursos e deve ser evitado)
4. Quando tenho apenas um processo, use kill para enviar um sinal para ele no linux
O processo recebe um sinal desconhecido (sinal nº 10), imprime o sinal definido pelo usuário 1, verifica o status do processo e descobre que o pid não pode ser encontrado, ou seja, é interrompido e destruído, como se tivesse jogado o função de matar o processo (o processo pai anterior envia um sinal desconhecido para o processo filho, mas ele fica travado). Então, para garantir a execução normal do processo, você precisa usar blindagem de sinal
Picadora de pequeno porte
Indique a fonte ao carregar
Desenvolvimento multiplataforma (Linux) baseado em VS2019 C++ (1.4.2) - com sinais de parâmetro
A máscara de sinal de aprendizagem é a seguinte