Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
In dit onderwerp wordt beschreven hoe u een eenvoudige toepassing op basis van agents maakt. In dit scenario kunt u een agent maken die gegevens asynchroon leest uit een tekstbestand. De toepassing maakt gebruik van het Adler-32-algoritme om de controlesom van de inhoud van dat bestand te berekenen.
Vereiste voorwaarden
U moet de volgende onderwerpen begrijpen om dit scenario te voltooien:
Afdelingen
In deze stap-voor-stap handleiding ziet u hoe u de volgende taken uitvoert:
De consoletoepassing maken
In deze sectie wordt beschreven hoe u een C++-consoletoepassing maakt die verwijst naar de headerbestanden die door het programma worden gebruikt. De eerste stappen variƫren, afhankelijk van de versie van Visual Studio die u gebruikt. Als u de documentatie voor uw voorkeursversie van Visual Studio wilt bekijken, gebruikt u het besturingselement voor versie-selector . Deze bevindt zich boven aan de inhoudsopgave op deze pagina.
Een C++-consoletoepassing maken in Visual Studio
Kies bestand>nieuw>project in het hoofdmenu om het dialoogvenster Een nieuw project maken te openen.
Stel bovenaan het dialoogvenster Taal in op C++, stel Platform in op Windows en stel Projecttype in op Console.
Kies Console-app in de gefilterde lijst met projecttypen en kies vervolgens Volgende. Voer
BasicAgentop de volgende pagina de naam voor het project in en geef desgewenst de projectlocatie op.Kies de knop Maken om het project te maken.
Klik met de rechtermuisknop op het projectknooppunt in Solution Explorer en kies Eigenschappen. Onder Configuratie-eigenschappen>C/C++>Vooraf gecompileerde headers>Vooraf gecompileerde header kies Aanmaken.
Een C++-consoletoepassing maken in Visual Studio 2017 en eerder
Klik in het menu Bestand op Nieuw en klik vervolgens op Project om het dialoogvenster Nieuw project weer te geven.
Selecteer in het dialoogvenster Nieuw project het knooppunt Visual C++ in het deelvenster Projecttypen en selecteer vervolgens Win32-consoletoepassing in het deelvenster Sjablonen . Typ bijvoorbeeld een naam voor het project
BasicAgenten klik vervolgens op OK om de wizard Win32-consoletoepassing weer te geven.Klik in het dialoogvenster wizard Win32-consoletoepassing op Voltooien.
Het headerbestand bijwerken
Voeg in het bestand pch.h (stdafx.h in Visual Studio 2017 en eerder) de volgende code toe:
#include <agents.h>
#include <string>
#include <iostream>
#include <algorithm>
De headerbestand agents.h bevat de functionaliteit van de gelijktijdigheid:::agentklasse .
De toepassing controleren
Controleer ten slotte of de toepassing succesvol is gemaakt door deze te bouwen en uit te voeren. Als u de toepassing wilt bouwen, klikt u in het menu Bouwen op Oplossing bouwen. Als de toepassing succesvol is gebouwd, voert u de toepassing uit door te klikken op Foutopsporing starten via het menu Foutopsporing.
[Boven]
De file_reader-klasse maken
In deze sectie ziet u hoe u de file_reader klasse maakt. De runtime plant elke agent om werk uit te voeren in zijn eigen context. Daarom kunt u een agent maken die synchroon werkt, maar asynchroon communiceert met andere onderdelen. De file_reader klasse leest gegevens uit een bepaald invoerbestand en verzendt gegevens uit dat bestand naar een bepaald doelonderdeel.
De file_reader-klasse maken
Voeg een nieuw C++-headerbestand toe aan uw project. Klik hiervoor met de rechtermuisknop op het knooppunt Header Files in Solution Explorer, klik op Toevoegen en klik vervolgens op Nieuw item. Selecteer in het deelvenster Sjablonende optie Koptekstbestand (.h).). Voer in het dialoogvenster Nieuw item toevoegen het vak
file_reader.hin en klik vervolgens op Toevoegen.Voeg in file_reader.h de volgende code toe.
#pragma onceMaak in file_reader.h een klasse met de naam
file_readerdie is afgeleid vanagent.class file_reader : public concurrency::agent { public: protected: private: };Voeg de volgende gegevensleden toe aan de
privatesectie van uw klas.std::string _file_name; concurrency::ITarget<std::string>& _target; concurrency::overwrite_buffer<std::exception> _error;Het
_file_namelid is de bestandsnaam waaruit de agent leest. Het_targetlid is een concurrentie::ITarget-object waarin de agent de inhoud van het bestand schrijft. Het_errorlid bevat elke fout die optreedt tijdens de levensduur van de agent.Voeg de volgende code voor de
file_readerconstructors toe aan depublicsectie van defile_readerklasse.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) { }Elke constructoroverload stelt de
file_readergegevensleden in. Met de tweede en derde constructoroverbelasting kan uw toepassing een specifieke taakplanner gebruiken met uw agent. De eerste overbelasting maakt gebruik van de standaardplanner met uw agent.Voeg de
get_errormethode toe aan de openbare sectie van defile_readerklasse.bool get_error(std::exception& e) { return try_receive(_error, e); }De
get_errormethode haalt elke fout op die zich voordoet tijdens de levensduur van de agent.Implementeer de gelijktijdigheid::agent::run-methode in het
protectedgedeelte van uw klasse.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(); }
De run methode opent het bestand en leest er gegevens uit. De run methode maakt gebruik van uitzonderingsafhandeling om fouten vast te leggen die optreden tijdens het verwerken van bestanden.
Telkens wanneer deze methode gegevens uit het bestand leest, wordt de gelijktijdigheidsfunctie::asend aangeroepen om die gegevens naar de doelbuffer te verzenden. De lege tekenreeks wordt naar de doelbuffer verzonden om het einde van de verwerking aan te geven.
In het volgende voorbeeld ziet u de volledige inhoud van 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;
};
[Boven]
De file_reader-klasse in de toepassing gebruiken
In deze sectie ziet u hoe u de file_reader klasse gebruikt om de inhoud van een tekstbestand te lezen. Het laat ook zien hoe u een object concurrency::call maakt dat deze bestandsgegevens ontvangt en de Adler-32-controlesom berekent.
De file_reader-klasse in uw toepassing gebruiken
Voeg in BasicAgent.cpp de volgende
#includeinstructie toe.#include "file_reader.h"Voeg in BasicAgent.cpp de volgende
usinginstructies toe.using namespace concurrency; using namespace std;Maak in de
_tmain-functie een concurrency::event-object aan dat het einde van de verwerking aangeeft.event e;Maak een
callobject waarmee de controlesom wordt bijgewerkt wanneer deze gegevens ontvangt.// 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; }); });Met dit
callobject wordt ook heteventobject ingesteld wanneer deze de lege tekenreeks ontvangt om het einde van de verwerking aan te geven.Maak een
file_readerobject dat wordt gelezen uit het bestand test.txt en schrijft de inhoud van dat bestand naar hetcallobject.file_reader reader("test.txt", calculate_checksum);Start de agent en wacht tot deze is voltooid.
reader.start(); agent::wait(&reader);Wacht totdat het
callobject alle gegevens ontvangt en klaar is.e.wait();Controleer de bestandslezer op fouten. Wanneer er geen fout is opgetreden, bereken de uiteindelijke Adler-32 som en druk de som af op de 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; }
In het volgende voorbeeld ziet u het volledige BasicAgent.cpp-bestand.
// 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;
}
}
[Boven]
Voorbeeldinvoer
Dit is de voorbeeldinhoud van het invoerbestand text.txt:
The quick brown fox
jumps
over the lazy dog
Voorbeelduitvoer
Wanneer dit programma wordt gebruikt met de voorbeeldinvoer, produceert dit programma de volgende uitvoer:
Adler-32 sum is fefb0d75
Robuuste programmering
Om gelijktijdige toegang tot gegevensleden te voorkomen, raden we u aan methoden toe te voegen die werk uitvoeren aan de protected of private sectie van uw klas. Voeg alleen methoden toe waarmee berichten naar of van de agent worden verzonden of ontvangen naar de public sectie van uw klasse.
Roep altijd de concurrency::agent::done methode aan om uw agent naar de voltooide status te verplaatsen. Normaal gesproken roept u deze methode aan voordat u terugkeert vanuit de run methode.
Volgende stappen
Zie Handleiding: Join gebruiken om impasses te voorkomen voor een ander voorbeeld van een agentgebaseerde toepassing.
Zie ook
Bibliotheek met asynchrone agents
Asynchrone berichtblokken
Functies voor het doorgeven van berichten
Synchronisatiegegevensstructuren
Handleiding: Join gebruiken om deadlock te voorkomen