Modelo IO (IO com bloqueio, IO sem bloqueio, IO acionado por sinal, IO assíncrono, IO multiplexado)

1. Cinco modelos IO típicos

  • IO com bloqueio, IO sem bloqueio, IO acionado por sinal, IO assíncrono, modelo de multiplexação.
  • O processo de IO:
    inicie uma chamada de IO, aguarde até que a condição de IO esteja pronta e, em seguida, copie os dados para o buffer para processamento - espere/copie.
1. Bloqueio de E/S:
  • Para completar o IO, uma chamada IO é iniciada. Se as condições de chamada não forem atendidas neste momento, ele aguardará até que as condições sejam atendidas e a chamada IO seja concluída.
    Bloqueio de E/S
  • O processo é muito simples. Somente após a conclusão de um IO é que a próxima chamada de IO pode ser feita. Os recursos não são totalmente utilizados e ficam em estado de espera na maior parte do tempo.
2. IO sem bloqueio:
  • Para concluir o IO, uma chamada é iniciada. Se as condições de IO não forem atendidas no momento, um erro será retornado imediatamente. (Normalmente retorne para realizar outras operações e inicie novamente as chamadas IO).
    IO sem bloqueio
  • Em comparação com o bloqueio de IO, a utilização de recursos é mais completa, mas as operações de IO não são em tempo real.
3. IO acionado por sinal:
  • Defina o método de processamento de IO do sinal, execute operações de IO no método de processamento, notifique o processo com o sinal de IO pronto e faça chamadas de IO quando o IO estiver pronto.
    IO acionado por sinal
  • Para IO orientado por sinal, o IO é mais em tempo real e utiliza totalmente os recursos, mas o processo de chamada é complicado.
4. E/S assíncrona:
  • Informe ao sistema operacional por meio de chamadas de E/S assíncronas quais dados de E/S são copiados e para onde. O processo de espera e o processo de cópia são concluídos pelo sistema operacional.
    E/S assíncrona
  • Os recursos são totalmente utilizados e o processo é mais complexo.

Nota:
①Bloqueio: Para concluir uma função, inicie uma chamada. Se as condições de conclusão não forem atendidas no momento, ela aguardará para sempre.
② Sem bloqueio: Para completar uma função, inicie uma chamada. Se as condições de conclusão não forem atendidas no momento, um erro será retornado diretamente.
③A diferença entre bloqueio e não bloqueio: se deve esperar quando a chamada é iniciada e a chamada não é concluída.
④Sincronização: Processo de processamento, processamento sequencial, após a conclusão de um, o outro é concluído. Todas as funções são concluídas pelo próprio processo.
⑤Assíncrono: No processo de processamento, o pedido é incerto porque as funções são concluídas pelo sistema operacional.
⑥Bloqueio assíncrono: a função é concluída por outras pessoas e a chamada está aguardando a conclusão de outras pessoas.
⑦Sem bloqueio assíncrono: a função é concluída por outros e a chamada retorna imediatamente.

2. E/S multiplexada

  • O monitoramento centralizado de eventos IO para um grande número de descritores pode informar ao programador/processo quais descritores estão prontos para quais eventos. Neste momento, o programador/processo pode responder diretamente aos descritores dos eventos correspondentes que estão prontos para evitar a execução de operações IO em operadores que não estão prontos resulta na redução da eficiência/bloqueio do fluxo do programa.
  • Eventos IO: eventos legíveis, eventos graváveis, eventos anormais;
  • Modelo IO de multiplexação: select/poll/epoll; usado para monitorar descritores.
1. selecione o modelo:
(1) Processo de operação :

① O programador define um conjunto de descritores para um determinado evento (conjunto de descritores para eventos legíveis/conjunto de descritores para eventos graváveis/conjunto de descritores para eventos de exceção), inicializa e limpa o conjunto e determina qual descritor se preocupa com qual evento. Este descritor é adicionado ao conjunto de descritores do evento correspondente.
②Copie a coleção para o kernel para monitoramento. O princípio do monitoramento é a votação e o julgamento transversal. Pronto para eventos legíveis: o tamanho dos dados no buffer de recebimento é maior que o limite mínimo (padrão quantificado – geralmente o padrão é um byte); Pronto para eventos graváveis: o tamanho do espaço restante no buffer de envio é maior do que o limite mínimo (padrão quantificado – geralmente o padrão é um byte) Geralmente o padrão é um byte); prontidão para eventos de exceção: se o descritor gera uma exceção.
③A chamada de monitoramento retorna, indicando um erro de monitoramento/descritor pronto/tempo limite de espera de monitoramento; e quando a chamada retorna, os descritores não prontos no conjunto de descritores de monitoramento de eventos são removidos do conjunto - (apenas pronto é retido no descritor de conjunto). Como a coleção é modificada ao retornar, será necessário adicionar operadores à coleção novamente na próxima vez que monitorar.
④O programador pesquisa para determinar em qual conjunto o descritor ainda está, determina se o descritor está pronto para um determinado evento e, em seguida, executa a operação correspondente ao evento; select não retorna diretamente o usuário ao descritor pronto para operação direta, mas Ele retorna um conjunto de descritores virtuais, portanto o programador precisa fazer um julgamento.

(2) Operação de código :

① Defina o conjunto - struct fd_set - O membro é um array, usado como um bitmap binário - adicionar um descritor significa definir a posição do bit correspondente ao valor do descritor como 1, então o número de descritores que o seclect pode monitorar depende dos bits de o bitmap binário O número de bits — o número de bits depende da macro (_FD_SETSIZE, o padrão é 1024);

  •   void FD_ZERO(fd_set* set);—初始化清空集合。
    
  •   void FD_SET(int fd, fd_set* set);—将操作符fd增加到set集合中。
    

②Iniciar interface de chamada:

  •   int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout);
      nfds:当前监控的集合中最大的描述符+1;减少遍历次数。
      readfds/writefd/exceptfds:可读/可写/异常三种事件的集合。
      timeout:时间的结构体。struct{tv_sec;tv_usec;},通过这个事件决定select阻塞/非阻塞/限制超时阻塞;
      	-若timeout为NULL,则表示阻塞监控,直到描述符就绪,或者监控出错才会返回。
      	-若timeout中的成员数据为0,则表示非阻塞,监控的时候若没有操作符就绪,则就立即超时返回。
      	-若timeout中成员数据不为0,则在指定时间内,没有就虚则超时返回。
      	返回值:返回值大于0表示就绪的描述符个数;返回值等于0表示没有棉袄舒服就绪,超时返回;返回值小于0表示监控出错。	
    

③A chamada retorna e devolve ao programador um conjunto de descritores prontos. O programador se desvia do julgamento de qual descritor ainda está no conjunto, qual é qual evento está pronto.

  •   int FD_ISSET(int fd, fd_set* set);—判断fd描述符是否在集合中;
    
  • Como a coleção será modificada quando select retornar, o descritor deverá ser adicionado novamente sempre que for monitorado.

④Se você não quiser mais monitorar o descritor, remova o descritor fd do conjunto

  •   void FD_CLR(int fd, fd_set* set);--从set集合中删除描述符fd;
    
(3) Selecione para monitorar a entrada padrão:
                                                                                                                                                                                                                                                  
   #include<stdio.h>
   #include<unistd.h>
   #include<string.h>
   #include<fcntl.h>
   #include<sys/select.h>
   
   int main()
   {
    
    
     // 对标准输入进行监控
    // 1.定义指定事件的集合
    fd_set rfds;
    while(1)
    {
    
    
      printf("开始监控\n");
      //selent(maxfsd+1,可读集合,可写集合,异常集合,超时时间)
      struct timeval tv;
      tv.tv_sec = 3;
      tv.tv_usec = 0;
      FD_ZERO(&rfds);//初始化清空集合
      FD_SET(0,&rfds);// 将0号描述符添加到集合中
      int res = select(0+1,&rfds,NULL,NULL,&tv);
      if(res < 0){
    
    
        perror("select error");
        return -1;
      }else if(res == 0){
    
    
        printf("wait timeout\n");
        continue;
      }
      if(FD_ISSET(0,&rfds)){
    
    //判断描述符是否在集合中判断是否就绪了事件
        printf("准备从标准输入读取数据:...\n");
        char buf[1024] = {
    
    0};
        int ret = read(0,buf,1023);
        if(ret<0)
        {
    
    
          perror("read error");
          FD_CLR(0,&rfds);//移除描述符从集合中
          return -1;
        }
        printf("read buf:[%s]\n",buf);
      }
    }
    return 0;
  } 
(4) Análise de vantagens e desvantagens:
  • Desvantagens :
    ① Select tem um limite máximo de número para descritores de monitoramento, e o limite superior depende da macro - _FD - SETSIZE, com tamanho padrão de 1024; ② O monitoramento
    no kernel é obtido através do julgamento de polling traversal, e o desempenho aumentará com o descritor. Aumentar e diminuir
    ③ só pode retornar o conjunto pronto, e o processo precisa percorrer o conjunto para saber qual descritor está pronto para qual evento.
    ④Cada monitoramento requer a readicionamento de descritores à coleção, e cada monitoramento requer a nova cópia da coleção para o kernel.
  • Vantagens :
    A portabilidade entre plataformas é relativamente boa e segue os padrões POSIX.
2. modelo de pesquisa:
(1) Processo de operação:

① Defina a matriz de estrutura de evento do descritor monitorado e adicione o descritor e as informações de identificação do evento a serem monitoradas a cada nó da matriz; ② Inicie uma chamada para iniciar o monitoramento e copie a matriz da estrutura de evento do descritor para o kernel para rotação. Consulta
transversal julgamento, se o tempo limite estiver pronto/espera, a chamada retornará e, em cada estrutura de evento pronto, o evento pronto atual será representado; ③
Realize a pesquisa e percorra a matriz para determinar qual evento o evento pronto está em cada nó da matriz. Determina se o descritor está pronto e o que fazer com ele.

(2) Operação de código:
  •   int poll(struct pollfd* arry_fds,nfds_t nfds,int timeout)
      poll---监控采用时间结构体的形式;
      struct pollfd {
      	int fd ;---要监控的描述符;
      	short events; --- 要监控的事件POLLIN/POLLOUT;
      	short revents; --- 调用返回是填充的就绪事件
      	arry_fds---事件结构体数组,填充要监控的描述符以及事件信息;
      	nfds --- 数组中的有效节点数个数;
      	timeout---监控事件超时等待事件;
      	返回值:返回值大于0表示就绪描述符事件的个数;返回值等于0就表示等待超时,返回值小于0表示监控出错。
    
  #include <poll.h>
  #include <unistd.h>
  #include <stdio.h>
  int main() {
    
    
    struct pollfd poll_fd;//定义事件结构体 
    poll_fd.fd = 0;
    poll_fd.events = POLLIN;//输入事件                                                                                    
    for (;;) {
    
    
      int ret = poll(&poll_fd, 1, 1000);
      if (ret < 0) {
    
    
        perror("poll");
	       continue; 
      }
      if (ret == 0) {
    
    
        printf("poll timeout\n");
        continue;
      }
      if (poll_fd.revents == POLLIN) {
    
    
        char buf[1024] = {
    
    0};
        read(0, buf, sizeof(buf) - 1);
        printf("stdin:%s", buf);
      }
    }
  }
(3) Análise de vantagens e desvantagens:
  • Vantagens :
    ① O uso de estruturas de eventos para monitoramento simplifica o processo de operação dos três eventos na seleção.
    ② Não há limite máximo para o número de descritores monitorados.
    ③Não há necessidade de redefinir nós de eventos todas as vezes.
  • Desvantagens :
    ①Má portabilidade entre plataformas.
    ②Cada monitoramento ainda requer a cópia dos dados de monitoramento para o kernel.
    ③ O monitoramento no kernel ainda usa polling traversal e o desempenho diminuirá à medida que o número de descritores aumentar.
Modelo 3.eppol:
  • O modelo de multiplexação mais útil e de melhor desempenho no Linux.
(1) Processo de operação:

① Iniciar uma chamada para criar a estrutura epollevent do identificador epoll no kernel (esta estrutura contém muitas informações, árvore vermelha e preta + lista vinculada bidirecional); ② Iniciar uma chamada para adicionar/excluir/modificar as informações de monitoramento do descritor
monitorado para a estrutura epollevent no kernel;
③Inicie o início do monitoramento, use operações de bloqueio assíncronas no kernel para implementar o monitoramento, aguarde o tempo limite/quando um descritor estiver pronto, ele retornará e retornará as informações da estrutura de eventos do descritor pronto do usuário ; ④O processo responde diretamente à descrição na
estrutura de eventos pronta. Basta usar os membros do símbolo para realizar operações.

(2) Informações da interface:

① Crie o identificador epoll eventpoll no kernel e retorne o descritor

  •   int epoll _create(int size); :返回epoll操作句柄
      	-size : 在linux2.6.2以后被忽略,只要大于0即可。
      	返回值:文件描述符--epoll的操作句柄
    

②epoll função de registro de tempo:

  •   int epoll_ctl(int epfd,int cmd, int fd, struct epoll_event* ev);
       -epfd : epoll_creat 返回的操作句柄;
       -cmd : 针对fd描述符的监控信息要进行的操作--添加/删除/修改 EPOLL_CTL_ADD/EPOLL_CTL_DEL/EPOLL_CTL_MOD;
       -fd : 要监控操作的描述符;
       -ev : fd描述符对应的事件结构体信息;
      	struct epoll_event{
      		uint32_t events; //对fd描述符要监控的事件--EPOLLIN/EPOLLOUT;
      		union{
      			int fd; // 监控操作的描述符;
      			void* ptr;//要填充的描述符信息;
      		}
      	}
    

③Colete eventos que foram enviados no evento de monitoramento epoll:

  •   int epoll_wait(int epfd,struct epoll_event *evs,int max_event,int timeout)
      	-epfd : epoll操作句柄;
      	-evs : struct epoll_event 结构体的首地址;
      	-max_event : 本次监控想要获取的就绪事件的最大数量,不大于evens数组的最大节点数量,禁止越界访问。
      	-timeout : 等待超时时间--单位:毫秒。
      	返回值:返回值<0 表示监控出错 ,返回值 == 0 表示超时返回 , 返回值 > 0 表示就绪的时间的个数。
    
(3) princípio de monitoramento epoll: operação de bloqueio assíncrono:
  • O monitoramento é concluído pelo sistema. O descritor de monitoramento e a estrutura de evento correspondente adicionada pelo usuário serão adicionados à árvore vermelha e preta na estrutura eventpoll do kernel. Depois que uma chamada é iniciada para iniciar o monitoramento, o sistema operacional faz um retorno de chamada para cada evento do descritor.Função, a função é adicionar a estrutura à lista duplamente vinculada quando o descritor estiver pronto para o evento de interesse.
  • O próprio processo apenas determina se a lista duplamente vinculada é NULL todas as vezes e determina se está pronta.
    ① Crie um identificador
    ② Adicione as informações do descritor monitorado e as informações da estrutura do evento correspondente ao kernel;
    ③ Inicie o monitoramento de bloqueio assíncrono e o sistema adicione as informações da estrutura do evento correspondente ao descritor pronto à lista duplamente vinculada;
    ④ Julgando a lista duplamente vinculada A estrutura do evento é retornada ao processo.
    ⑤ O processo só precisa determinar a operação correspondente no descritor enviado na estrutura de tempo com base nas informações de tempo na estrutura de evento pronta.
(4) Vantagens e desvantagens:
  • Vantagens :
    ① Não há limite máximo para o número de monitoramento sem descritor;
    ② As informações de monitoramento só precisam ser adicionadas ao kernel uma vez;
    ③ O monitoramento usa operações de bloqueio assíncronas e o desempenho não diminuirá com o aumento de operadores;
    ④ Diretamente retorna o tempo de prontidão para as informações do usuário, o processo opera diretamente no descritor e evento retornado, sem julgar se está pronto.
  • Desvantagens :
    Fraca portabilidade entre plataformas.
(5) Método de disparo em epoll:
  • Suponha que exista um exemplo :
    adicionamos um soquete tcp ao descritor epoll.
    Neste momento, 2 KB de dados são gravados na outra extremidade do soquete.
    Chame epoll_wait e ele retornará. Isso significa que está pronto para a operação de leitura
    e depois chama read, apenas 1 KB de dados foi lido
    e continuou a chamar epoll_wait

①Método de disparo horizontal:

  • O estado padrão do epoll é o modo de trabalho LT :
    quando o epoll detecta que o evento no soquete está pronto, ele não precisa processá-lo imediatamente. Ou processa apenas parte dele;
    como no exemplo acima, já que apenas 1K dados foram read, ainda há 1K de dados restantes no buffer. , quando epoll_wait for chamado pela segunda vez, epoll_wait ainda retornará imediatamente e notificará o soquete que o evento de leitura está pronto; epoll_wait não retornará imediatamente até que todos os dados no
    buffer foi processado,
    ou seja, suporta leitura e gravação com bloqueio e leitura sem bloqueio.

②Método de disparo de borda:

  • Se usarmos o sinalizador EPOLLET ao adicionar o soquete ao descritor epoll na etapa 1, o epoll entra no modo de trabalho ET: quando
    o epoll detecta que o evento no soquete está pronto, ele deve ser processado imediatamente;
    como no exemplo acima, embora apenas 1K foi lido Há 1K de dados restantes no buffer. Quando epoll_wait for chamado pela segunda vez, epoll_wait não retornará; ou seja,
    no modo ET, depois que o evento no descritor de arquivo estiver pronto, haverá apenas uma oportunidade de processamento;
    ET O desempenho é superior ao do LT (epoll_wait retorna muito menos vezes). O Nginx usa o modo ET para usar o epoll por padrão. Ou seja:
    ele suporta apenas leitura e gravação sem bloqueio.
  • A seleção e a votação realmente funcionam no modo LT. O epoll pode suportar tanto LT quanto ET.

Acho que você gosta

Origin blog.csdn.net/weixin_42357849/article/details/107785775
Recomendado
Clasificación