Compartilhar via


Demonstra Passo a passo: Criando um aplicativo baseado em agente

Este tópico descreve como criar um aplicativo de baseado em agente básico. Esta explicação passo a passo, você pode criar um agente que lê dados de um arquivo de texto de forma assíncrona. O aplicativo usa o algoritmo de soma de verificação Adler-32 para calcular a soma de verificação do conteúdo do arquivo.

Pré-requisitos

Você deve compreender os tópicos a seguir para concluir este passo a passo:

Seções

Esta explicação passo a passo demonstra como realizar as seguintes tarefas:

  • Criando o aplicativo de Console

  • Criando a classe de file_reader

  • Usando a classe de file_reader no aplicativo

Criando o aplicativo de Console

Esta seção mostra como criar um aplicativo de console do Visual C++ que faz referência os arquivos de cabeçalho, o programa usará.

Para criar um aplicativo do Visual C++ usando o Assistente de aplicativo do Console Win32

  1. No arquivo menu, clique em novae, em seguida, clique em projeto para exibir o Novo projeto caixa de diálogo.

  2. No Novo projeto caixa de diálogo, selecione o Visual C++ nó na tipos de projeto painel e selecione Aplicativo de Console do Win32 na modelos painel. Digite um nome para o projeto, por exemplo, BasicAgente em seguida, clique em OK para exibir o Assistente de aplicativo de Console do Win32.

  3. No Assistente de aplicativo de Console do Win32 caixa de diálogo, clique em Concluir.

  4. Em stdafx. h, adicione o seguinte código.

    #include <agents.h>
    #include <string>
    #include <iostream>
    #include <algorithm>
    

    O agents.h do arquivo de cabeçalho contém a funcionalidade da Concurrency::agent classe.

  5. Verifique se o aplicativo foi criado com êxito, criando e executando-o. Para criar o aplicativo, na Build menu, clique em Build Solution. Se o aplicativo foi criado com êxito, execute o aplicativo, clicando em Start Debugging sobre o Debug menu.

go to top

Criando a classe de file_reader

Esta seção mostra como criar o file_reader classe. O runtime agenda cada agente para realizar o trabalho em seu próprio contexto. Portanto, você pode criar um agente que realiza trabalho de forma síncrona, mas interage com outros componentes de forma assíncrona. O file_reader classe lê dados de um determinado arquivo de entrada e envia dados a partir desse arquivo para um componente de destino fornecido.

Para criar a classe file_reader

  1. Adicione um novo arquivo de cabeçalho do C++ para seu projeto. Para fazer isso, clique com o botão direito do Arquivos de cabeçalho nó na Solution Explorer, clique em Adde, em seguida, clique em Novo Item. No modelos de painel, selecione O arquivo de cabeçalho (. h). No Add New Item caixa de diálogo, digite file_reader.h no nome caixa e, em seguida, clique em Add.

  2. No file_reader.h, adicione o seguinte código.

    #pragma once
    
  3. No file_reader.h, criar uma classe chamada file_reader que deriva de agent.

    class file_reader : public Concurrency::agent
    {
    public:
    protected:
    private:
    };
    
  4. Adicione os seguintes membros de dados para o private seção da sua turma.

    std::string _file_name;
    Concurrency::ITarget<std::string>& _target;
    Concurrency::overwrite_buffer<std::exception> _error;
    

    O _file_name membro é o nome do arquivo que o agente lê. O _target membro é um Concurrency::ITarget que o agente grava o conteúdo do arquivo de objeto. O _error membro mantém qualquer erro que ocorre durante a vida útil do agente.

  5. Adicione o seguinte código para o file_reader construtores para o public seção a file_reader classe.

    explicit file_reader(const std::string& file_name, 
       Concurrency::ITarget<std::string>& target)
       : _file_name(file_name)
       , _target(target)
    {
    }
    
    explicit file_reader(const std::string& file_name, 
       Concurrency::ITarget<std::string>& target,
       Concurrency::Scheduler& scheduler)
       : agent(scheduler)
       , _file_name(file_name)
       , _target(target)
    {
    }
    
    explicit file_reader(const std::string& file_name, 
       Concurrency::ITarget<std::string>& target,
       Concurrency::ScheduleGroup& group)
       : agent(group) 
       , _file_name(file_name)
       , _target(target)
    {
    }
    

    Cada sobrecarga de construtor define o file_reader membros de dados. A sobrecarga do construtor de segundo e terceiro permite que seu aplicativo para usar o Agendador de específico com seu agente. A primeira sobrecarga usa o agendador padrão com o seu agente.

  6. Adicionar o get_error método para a seção pública da file_reader classe.

    bool get_error(std::exception& e)
    {
       return try_receive(_error, e);
    }
    

    O get_error método recupera qualquer erro que ocorre durante a vida útil do agente.

  7. Implementar a Concurrency::agent::run método de protected seção da sua turma.

    void run()
    {
       FILE* stream;
       try
       {
          // Open the file.
          if (fopen_s(&stream, _file_name.c_str(), "r") != 0)
          {
             // Throw an exception if an error occurs.            
             throw std::exception("Failed to open input file.");
          }
    
          // Create a buffer to hold file data.
          char buf[1024];
    
          // Set the buffer size.
          setvbuf(stream, buf, _IOFBF, sizeof buf);
    
          // Read the contents of the file and send the contents
          // to the target.
          while (fgets(buf, sizeof buf, stream))
          {
             asend(_target, std::string(buf));
          }   
    
          // Send the empty string to the target to indicate the end of processing.
          asend(_target, std::string(""));
    
          // Close the file.
          fclose(stream);
       }
       catch (const std::exception& e)
       {
          // Send the empty string to the target to indicate the end of processing.
          asend(_target, std::string(""));
    
          // Write the exception to the error buffer.
          send(_error, e);
       }
    
       // Set the status of the agent to agent_done.
       done();
    }
    

    O run método abre o arquivo e lê os dados do proprietário. O run método usa o tratamento de exceção para capturar quaisquer erros que ocorrem durante o processamento do arquivo.

    Cada vez que este método lê os dados do arquivo, ele chama o Concurrency::asend a função de enviar esses dados para o buffer de destino. Ele envia a seqüência de caracteres vazia para o buffer de destino para indicar o final do processamento.

O exemplo a seguir mostra todo o conteúdo da file_reader.h.

#pragma once

class file_reader : public Concurrency::agent
{
public:
   explicit file_reader(const std::string& file_name, 
      Concurrency::ITarget<std::string>& target)
      : _file_name(file_name)
      , _target(target)
   {
   }

   explicit file_reader(const std::string& file_name, 
      Concurrency::ITarget<std::string>& target,
      Concurrency::Scheduler& scheduler)
      : agent(scheduler)
      , _file_name(file_name)
      , _target(target)
   {
   }

   explicit file_reader(const std::string& file_name, 
      Concurrency::ITarget<std::string>& target,
      Concurrency::ScheduleGroup& group)
      : agent(group) 
      , _file_name(file_name)
      , _target(target)
   {
   }

   // Retrieves any error that occurs during the life of the agent.
   bool get_error(std::exception& e)
   {
      return try_receive(_error, e);
   }

protected:
   void run()
   {
      FILE* stream;
      try
      {
         // Open the file.
         if (fopen_s(&stream, _file_name.c_str(), "r") != 0)
         {
            // Throw an exception if an error occurs.            
            throw std::exception("Failed to open input file.");
         }

         // Create a buffer to hold file data.
         char buf[1024];

         // Set the buffer size.
         setvbuf(stream, buf, _IOFBF, sizeof buf);

         // Read the contents of the file and send the contents
         // to the target.
         while (fgets(buf, sizeof buf, stream))
         {
            asend(_target, std::string(buf));
         }   

         // Send the empty string to the target to indicate the end of processing.
         asend(_target, std::string(""));

         // Close the file.
         fclose(stream);
      }
      catch (const std::exception& e)
      {
         // Send the empty string to the target to indicate the end of processing.
         asend(_target, std::string(""));

         // Write the exception to the error buffer.
         send(_error, e);
      }

      // Set the status of the agent to agent_done.
      done();
   }

private:
   std::string _file_name;
   Concurrency::ITarget<std::string>& _target;
   Concurrency::overwrite_buffer<std::exception> _error;
};

go to top

Usando a classe de file_reader no aplicativo

Esta seção mostra como usar o file_reader classe para ler o conteúdo de um arquivo de texto. Ele também mostra como criar um Concurrency::call o objeto que recebe esse dados de arquivo e calcula a soma de verificação Adler-32.

Para usar a classe de file_reader em seu aplicativo.

  1. Em BasicAgent.cpp, adicione o seguinte #include instrução.

    #include "file_reader.h"
    
  2. Em BasicAgent.cpp, adicione o seguinte using diretivas.

    using namespace Concurrency;
    using namespace std;
    
  3. No _tmain funcionar, crie um Concurrency::event o objeto que sinaliza o final do processamento.

    event e;
    
  4. Criar um call objeto que atualiza a soma de verificação quando ele recebe dados.

    // The components of the Adler-32 sum.
    unsigned int a = 1;
    unsigned int b = 0;
    
    // A call object that updates the checksum when it receives data.
    call<string> calculate_checksum([&] (string s) {
       // If the input string is empty, set the event to signal
       // the end of processing.
       if (s.size() == 0)
          e.set();
       // Perform the Adler-32 checksum algorithm.
       for_each(s.begin(), s.end(), [&] (char c) {
          a = (a + c) % 65521;
          b = (b + a) % 65521;
       });
    });
    

    Isso call objeto também define o event o objeto quando ele recebe a seqüência de caracteres vazia para sinalizar o final do processamento.

  5. Criar um file_reader o objeto que lê a partir do txt de arquivo e grava o conteúdo desse arquivo para o call objeto.

    file_reader reader("test.txt", calculate_checksum);
    
  6. Inicie o agente e aguardar sua conclusão.

    reader.start();
    agent::wait(&reader);
    
  7. Aguarde até que o call o objeto para receber todos os dados e concluir.

    e.wait();
    
  8. Verifique se o leitor de arquivo de erros. Se nenhum erro ocorreu, calcular a soma de Adler-32 final e imprimir a soma ao console.

    std::exception error;
    if (reader.get_error(error))
    {
       wcout << error.what() << endl;
    }   
    else
    {      
       unsigned int adler32_sum = (b << 16) | a;
       wcout << L"Adler-32 sum is " << hex << adler32_sum << endl;
    }
    

O exemplo a seguir mostra o arquivo completo do BasicAgent.cpp.

// BasicAgent.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "file_reader.h"

using namespace Concurrency;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
   // An event object that signals the end of processing.
   event e;

   // The components of the Adler-32 sum.
   unsigned int a = 1;
   unsigned int b = 0;

   // A call object that updates the checksum when it receives data.
   call<string> calculate_checksum([&] (string s) {
      // If the input string is empty, set the event to signal
      // the end of processing.
      if (s.size() == 0)
         e.set();
      // Perform the Adler-32 checksum algorithm.
      for_each(s.begin(), s.end(), [&] (char c) {
         a = (a + c) % 65521;
         b = (b + a) % 65521;
      });
   });

   // Create the agent.
   file_reader reader("test.txt", calculate_checksum);

   // Start the agent and wait for it to complete.
   reader.start();
   agent::wait(&reader);

   // Wait for the call object to receive all data and complete.
   e.wait();

   // Check the file reader for errors.
   // If no error occurred, calculate the final Adler-32 sum and print it 
   // to the console.
   std::exception error;
   if (reader.get_error(error))
   {
      wcout << error.what() << endl;
   }   
   else
   {      
      unsigned int adler32_sum = (b << 16) | a;
      wcout << L"Adler-32 sum is " << hex << adler32_sum << endl;
   }
}

go to top

Entrada de exemplo

Este é o conteúdo de amostra de text.txt o arquivo de entrada:

The quick brown fox
jumps
over the lazy dog

Saída de exemplo

Quando usado com a entrada de exemplo, este programa produz a seguinte saída:

Adler-32 sum is fefb0d75

Programação robusta

Para impedir o acesso simultâneo aos membros de dados, recomendamos que você adicione métodos que realizam um trabalho para o protected ou private seção da sua turma. Adicione apenas os métodos que enviar ou recebem mensagens de ou para o agente para o public seção da sua turma.

Sempre chamar o Concurrency::agent:: feito método para mover o seu agente para o estado concluído. Normalmente você chamar esse método antes de retornar a partir de run método.

Próximas etapas

Outro exemplo de um aplicativo baseado em agente, consulte Demonstra Passo a passo: Usando a associação para evitar o Deadlock.

Consulte também

Tarefas

Demonstra Passo a passo: Usando a associação para evitar o Deadlock

Conceitos

Biblioteca de agentes assíncronos

Blocos de mensagens assíncronas

Funções de transmissão de mensagens

Estruturas de dados de sincronização