Sdílet prostřednictvím


Návod: Vytvoření aplikace založené na agentovi

Toto téma popisuje, jak vytvořit základní aplikace agenta.V tomto návodu můžete vytvořit agenta, který načítá data z textového souboru asynchronně.Aplikace používá algoritmus kontrolního součtu Adler-32 k výpočtu kontrolního součtu obsahu tohoto souboru.

Požadavky

Je třeba pochopit následující témata pro dokončení tohoto návodu:

Oddíly

Tento návod ukazuje, jak provádět následující úkoly:

  • Vytvoření konzolové aplikace

  • Vytvoření třídy file_reader

  • Používání třídy file_reader v aplikaci

Vytvoření konzolové aplikace

Tento oddíl ukazuje, jak vytvořit konzoly aplikace Visual C++, který odkazuje na soubory hlaviček, které program použije.

Vytvoření aplikace Visual C++ pomocí Průvodce konzolovou aplikací Win32

  1. Na souboru nabídky, klepněte na tlačítko Novýa potom klepněte na tlačítko projektu Chcete-li zobrazit Nový projekt dialogové okno.

  2. V Nový projekt vyberte položku Visual C++ uzlu v typy projektů podokna a pak vyberte Aplikace konzoly Win32 v šablony podokno.Zadejte název projektu, například BasicAgenta potom klepněte na tlačítko OK Chcete-li zobrazit Průvodce aplikace konzoly Win32.

  3. V Průvodce aplikace konzoly Win32 dialogové okno, klepněte na tlačítko Dokončit.

  4. Ve stdafx.h přidejte následující kód.

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

    Agents.h soubor záhlaví obsahuje funkce concurrency::agent třídy.

  5. Ověřte, že aplikace byla úspěšně vytvořena vytvořením a spuštěním.Při vytvoření aplikace, sestavení nabídky, klepněte na tlačítko Sestavit řešení.Pokud aplikace vytvoří úspěšně, spusťte aplikaci klepnutím na Spuštění ladění v ladění nabídky.

[Nahoře]

Vytvoření třídy file_reader

Tento oddíl ukazuje, jak vytvořit file_reader třídy.Modul runtime plánuje každý agent vykonávat práci ve vlastním kontextu.Proto můžete vytvořit agenta, který provede práce synchronně, ale spolupracuje s jinými součástmi asynchronně.file_reader Třídy načte data z daného vstupního souboru a odešle data z tohoto souboru na danou cílovou součást.

Vytvoření třídy file_reader

  1. Přidání nového souboru záhlaví C++ do projektu.Chcete-li tak učinit, klepněte pravým tlačítkem myši Soubory hlaviček uzlu v Průzkumník řešení, klepněte na tlačítko Přidata potom klepněte na tlačítko Novou položku.V šablony podokno, vyberte Soubor (hlaviček).V Přidat novou položku dialogové okno, typ file_reader.h v jméno a klepněte na tlačítko Přidat.

  2. V file_reader.h přidejte následující kód.

    #pragma once
    
  3. V file_reader.h, vytvořte třídu s názvem file_reader , je odvozen z agent.

    class file_reader : public concurrency::agent
    {
    public:
    protected:
    private:
    };
    
  4. Přidat následující datových členů ke private část vaší třídy.

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

    _file_name Je název souboru, který načte agent z člen._target Člen je concurrency::ITarget objektu, že agent zapíše obsah souboru._error Člen obsahuje všechny chyby, ke kterým dochází během života agent.

  5. Přidejte následující kód pro file_reader pro konstruktory public část file_reader třídy.

    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)
    {
    }
    

    Každé přetížení konstruktor nastaví file_reader datových členů.Přetížení konstruktoru druhý a třetí umožňuje aplikacím používat určité Plánovač vašeho agenta.První přetížení používá výchozí plánovač vašeho agenta.

  6. Přidat get_error metoda na veřejné části file_reader třídy.

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

    get_error Metoda načte všechny chyby, ke kterým dochází během života agent.

  7. Implementovat concurrency::agent::run metoda protected část vaší třídy.

    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();
    }
    

    run Metoda otevře soubor a přečte data z něj.run Metoda používá k zachycení chyby, ke kterým dochází při zpracování souboru zpracování výjimek.

    Tato metoda načte data ze souboru při každém volání concurrency::asend funkce pro odeslání dat do cílové vyrovnávací paměti.Cílové vyrovnávací paměti pro označení konce zpracování odešle prázdný řetězec.

Následující příklad ukazuje kompletní obsah 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;
};

[Nahoře]

Používání třídy file_reader v aplikaci

Tento oddíl ukazuje, jak použít file_reader třídy k načtení obsahu textového souboru.Také ukazuje, jak vytvořit concurrency::call objekt, který přijímá data tohoto souboru a vypočítá kontrolní součet jeho Adler-32.

Použití třídy file_reader v aplikaci

  1. V BasicAgent.cpp, přidejte následující #include prohlášení.

    #include "file_reader.h"
    
  2. V BasicAgent.cpp, přidejte následující using směrnice.

    using namespace concurrency;
    using namespace std;
    
  3. V _tmain funkce, vytvořit concurrency::event objekt, který označuje konec zpracování.

    event e;
    
  4. Vytvořit call objekt, který poté, co obdrží data aktualizuje kontrolní součet.

    // 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(begin(s), end(s), [&] (char c) {
          a = (a + c) % 65521;
          b = (b + a) % 65521;
       });
    });
    

    To call objekt také nastaví event objektu poté, co obdrží signál konce zpracování na prázdný řetězec.

  5. Vytvořit file_reader objekt, který čte ze souboru test.txt a obsah souboru se zapíše call objektu.

    file_reader reader("test.txt", calculate_checksum);
    
  6. Spuštění agenta a počkejte na její dokončení.

    reader.start();
    agent::wait(&reader);
    
  7. Čekání call objekt, který chcete zobrazit všechna data a dokončení.

    e.wait();
    
  8. Zkontrolujte soubor čtečka chyb.Pokud nedošlo k žádné chybě, vypočítat konečný součet Adler-32 a vytisknout součet do konzoly.

    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;
    }
    

Následující příklad ukazuje kompletní soubor 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(begin(s), end(s), [&] (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;
   }
}

[Nahoře]

Ukázkový vstup

Toto je ukázkový obsah vstupního souboru text.txt:

  

Výstup ukázky

Při použití s ukázkový vstup, program vytvoří následující výstup:

  

Robustní programování

Chcete-li zabránit souběžný přístup k datové členy, doporučujeme přidat metody, které provádějí práce protected nebo private část vaší třídy.Metody, které slouží k odesílání a přijímání zpráv z agent nebo přidat pouze public část vaší třídy.

Vždy volat concurrency::agent:: v metoda k přesunutí vašeho agenta do dokončeného stavu.Před vrácením z obvykle volání této metody run metody.

Další kroky

Dalším příkladem aplikace založené na agenta v Návod: Použití metody join k zabránění vzájemnému zablokování.

Viz také

Úkoly

Návod: Použití metody join k zabránění vzájemnému zablokování

Koncepty

Knihovna asynchronních agentů

Asynchronní bloky zpráv

Funkce usnadnění

Synchronizační datové struktury