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
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.
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.
V Průvodce aplikace konzoly Win32 dialogové okno, klepněte na tlačítko Dokončit.
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.
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
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.
V file_reader.h přidejte následující kód.
#pragma once
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: };
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.
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.
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.
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
V BasicAgent.cpp, přidejte následující #include prohlášení.
#include "file_reader.h"
V BasicAgent.cpp, přidejte následující using směrnice.
using namespace concurrency; using namespace std;
V _tmain funkce, vytvořit concurrency::event objekt, který označuje konec zpracování.
event e;
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.
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);
Spuštění agenta a počkejte na její dokončení.
reader.start(); agent::wait(&reader);
Čekání call objekt, který chcete zobrazit všechna data a dokončení.
e.wait();
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í