Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I det här avsnittet beskrivs hur du skapar ett grundläggande agentbaserat program. I den här genomgången kan du skapa en agent som läser data från en textfil asynkront. Programmet använder algoritmen Adler-32 checksum för att beräkna kontrollsumman för innehållet i filen.
Förutsättningar
Du måste förstå följande avsnitt för att slutföra den här genomgången:
Sektioner
Den här genomgången visar hur du utför följande uppgifter:
Skapa konsolprogrammet
Det här avsnittet visar hur du skapar ett C++-konsolprogram som refererar till huvudfilerna som programmet ska använda. De första stegen varierar beroende på vilken version av Visual Studio du använder. Om du vill se dokumentationen för din föredragna version av Visual Studio använder du väljarkontrollen Version. Den finns överst i innehållsförteckningen på den här sidan.
Skapa ett C++-konsolprogram i Visual Studio
- På huvudmenyn väljer du Arkiv>Nytt>projekt för att öppna dialogrutan Skapa ett nytt projekt . 
- Längst upp i dialogrutan anger du Språk till C++, anger Plattform till Windows och anger Projekttyp till Konsol. 
- I den filtrerade listan över projekttyper väljer du Konsolapp och sedan Nästa. På nästa sida anger du - BasicAgentsom namn på projektet och anger projektplatsen om du vill.
- Välj knappen Skapa för att skapa projektet. 
- Högerklicka på projektnoden i Solution Explorer och välj Egenskaper. Under Konfigurationsegenskaper>C/C++>Förkompilerade rubriker>Förkompilerat sidhuvud väljer du Skapa. 
Skapa ett C++-konsolprogram i Visual Studio 2017 och tidigare
- På Arkiv-menyn klickar du på Nytt och sedan på Projekt för att visa dialogrutan Nytt projekt . 
- I dialogrutan Nytt projekt väljer du noden Visual C++ i fönstret Projekttyper och väljer sedan Win32-konsolprogram i fönstret Mallar . Skriv ett namn för projektet, till exempel - BasicAgent, och klicka sedan på OK för att visa guiden Win32-konsolprogram.
- I dialogrutan Programguide för Win32-konsol klickar du på Slutför. 
Uppdatera rubrikfilen
Lägg till följande kod i filen pch.h (stdafx.h i Visual Studio 2017 och tidigare):
#include <agents.h>
#include <string>
#include <iostream>
#include <algorithm>
Huvudfilen agents.h innehåller funktionerna i klassen concurrency::agent .
Verifiera programmet
Kontrollera slutligen att programmet har skapats framgångsrikt genom att bygga och köra det. Om du vill skapa programmet går du till menyn Skapa och klickar på Skapa lösning. Om programmet har skapats framgångsrikt, kör du programmet genom att klicka på Starta felsökning på felsökningsmenyn.
[Topp]
Skapa file_reader-klassen
Det här avsnittet visar hur du skapar file_reader-klassen. Körningsmiljön schemalägger varje agent för att utföra arbete i sin egen kontext. Därför kan du skapa en agent som utför arbetet synkront, men som interagerar med andra komponenter asynkront. Klassen file_reader läser data från en angiven indatafil och skickar data från den filen till en viss målkomponent.
Skapa klassen file_reader
- Lägg till en ny C++-huvudfil i projektet. Det gör du genom att högerklicka på noden Rubrikfiler i Solution Explorer, klicka på Lägg till och sedan på Nytt objekt. I fönstret Mallar väljer du Rubrikfil (.h). I dialogrutan Lägg till nytt objekt skriver du - file_reader.hi rutan Namn och klickar sedan på Lägg till.
- Lägg till följande kod i file_reader.h. - #pragma once
- I file_reader.h skapar du en klass med namnet - file_readersom härleds från- agent.- class file_reader : public concurrency::agent { public: protected: private: };
- Lägg till följande datamedlemmar i - private-avsnittet i din klass.- std::string _file_name; concurrency::ITarget<std::string>& _target; concurrency::overwrite_buffer<std::exception> _error;- Elementet - _file_nameär det filnamn som agenten läser från. Medlemmen- _targetär ett concurrency::ITarget-objekt till vilket agenten skriver innehållet i filen. Medlemmen- _errorinnehåller eventuella fel som inträffar under agentens livstid.
- Lägg till följande kod för - file_readerkonstruktorerna i- publicavsnittet i- file_readerklassen.- 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) { }- Varje konstruktoröverlagring anger - file_readerdatamedlemmarna. Med den andra och tredje konstruktorns överlagring kan ditt program använda en specifik schemaläggare med din agent. Den första överlagringen använder standardschemaläggaren med din agent.
- Lägg till metoden - get_errori den offentliga delen av klassen- file_reader.- bool get_error(std::exception& e) { return try_receive(_error, e); }- Metoden - get_errorhämtar eventuella fel som inträffar under agentens livslängd.
- Implementera metoden concurrency::agent::run i - protectedavsnittet i klassen.- 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(); }
Metoden run öppnar filen och läser data från den. Metoden run använder undantagshantering för att samla in eventuella fel som inträffar under filbearbetningen.
Varje gång den här metoden läser data från filen anropas funktionen concurrency::asend för att skicka dessa data till målbufferten. Den skickar den tomma strängen till målbufferten för att indikera slutet på bearbetningen.
I följande exempel visas det fullständiga innehållet i 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;
};
[Topp]
Använda file_reader-klassen i programmet
Det här avsnittet visar hur du använder file_reader klassen för att läsa innehållet i en textfil. Den visar också hur du skapar ett concurrency::call-objekt som tar emot fildata och beräknar Adler-32-kontrollsumman.
Så här använder du klassen file_reader i ditt program
- Lägg till följande - #includeinstruktion i BasicAgent.cpp.- #include "file_reader.h"
- Lägg till följande - usingdirektiv i BasicAgent.cpp.- using namespace concurrency; using namespace std;
- _tmainI funktionen skapar du ett samtidighet::händelseobjekt som signalerar slutet på bearbetningen.- event e;
- Skapa ett - callobjekt som uppdaterar kontrollsumman när den tar emot data.- // 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; }); });- Det här - callobjektet anger även- eventobjektet när det tar emot den tomma strängen för att signalera slutet av bearbetningen.
- Skapa ett - file_readerobjekt som läser från filen test.txt och skriver innehållet i filen till- callobjektet.- file_reader reader("test.txt", calculate_checksum);
- Starta agenten och vänta tills den är klar. - reader.start(); agent::wait(&reader);
- Vänta tills objektet - callhar fått alla data och slutförts.- e.wait();
- Kontrollera om det finns fel i filläsaren. Om inget fel uppstod beräknar du den slutliga Adler-32-summan och skriver ut summan till konsolen. - 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; }
I följande exempel visas den fullständiga BasicAgent.cpp filen.
// BasicAgent.cpp : Defines the entry point for the console application.
//
#include "pch.h" // Use stdafx.h in Visual Studio 2017 and earlier
#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;
   }
}
[Topp]
Exempel på indata
Det här är exempelinnehållet i indatafilen text.txt:
The quick brown fox
jumps
over the lazy dog
Exempelutdata
När det används med exempelindata genererar det här programmet följande utdata:
Adler-32 sum is fefb0d75
Robust Programmering
För att förhindra samtidig åtkomst till datamedlemmar rekommenderar vi att du lägger till metoder som utför arbete i protected avsnittet eller private i din klass. Lägg bara till metoder som skickar eller tar emot meddelanden till eller från agenten i avsnittet i public klassen.
Anropa alltid samtidighet::agent::done metoden för att flytta agenten till slutfört tillstånd. Du anropar vanligtvis den här metoden innan du kommer tillbaka från run metoden.
Nästa steg
Ett annat exempel på ett agentbaserat program finns i Genomgång: Använda koppling för att förhindra dödläge.
Se även
              Asynkront agentbibliotek
              Asynkrona meddelandeblock
              Funktioner för meddelandeöverföring
              Datastrukturer för synkronisering
              Genomgång: Använda join för att förhindra dödläge