Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Toto téma popisuje, jak vytvořit základní aplikaci založenou na agentech. V tomto názorném postupu můžete vytvořit agenta, který čte 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
Abyste mohli tento návod dokončit, musíte porozumět následujícím tématům:
Oddíly
Tento názorný postup ukazuje, jak provádět následující úlohy:
Vytvoření konzolové aplikace
Tato část ukazuje, jak vytvořit konzolovou aplikaci jazyka C++, která odkazuje na soubory hlaviček, které bude program používat. Počáteční kroky se liší v závislosti na tom, jakou verzi sady Visual Studio používáte. Pokud chcete zobrazit dokumentaci pro upřednostňovanou verzi sady Visual Studio, použijte ovládací prvek selektoru verzí . Nachází se v horní části obsahu na této stránce.
Vytvoření konzolové aplikace jazyka C++ v sadě Visual Studio
V hlavní nabídce zvolte Soubor>nový>projekt a otevřete dialogové okno Vytvořit nový projekt.
V horní části dialogového okna nastavte jazyk na C++, nastavte platformu pro Windows a nastavte typ projektu na konzolu.
V filtrovaném seznamu typů projektů zvolte Konzolová aplikace a pak zvolte Další. Na další stránce zadejte
BasicAgentjako název projektu a v případě potřeby zadejte umístění projektu.Zvolte tlačítko Vytvořit a vytvořte projekt.
Pravým tlačítkem myši klikněte na uzel projektu v Průzkumník řešení a zvolte Vlastnosti. V části Vlastnosti>konfigurace C/C++>Předkompilované hlavičky předkompilované hlavičky> zvolte Vytvořit.
Vytvoření konzolové aplikace C++ v sadě Visual Studio 2017 a starších verzích
V nabídce Soubor klepněte na tlačítko Nový a klepněte na tlačítko Projekt zobrazte dialogové okno Nový projekt.
V dialogovém okně Nový projekt vyberte uzel Visual C++ v podokně Typy projektů a pak v podokně Šablony vyberte konzolovou aplikaci Win32. Zadejte název projektu, například
BasicAgenta klepněte na tlačítko OK zobrazte Průvodce konzolovou aplikací Win32.V dialogovém okně Průvodce konzolovou aplikací Win32 klepněte na tlačítko Dokončit.
Aktualizace souboru záhlaví
Do souboru pch.h (stdafx.h v sadě Visual Studio 2017 a starší) přidejte následující kód:
#include <agents.h>
#include <string>
#include <iostream>
#include <algorithm>
Agenti souborů hlaviček.h obsahují funkce třídy concurrency::agent .
Ověření aplikace
Nakonec ověřte, že se aplikace úspěšně vytvořila, a to tak, že ji sestavíte a spustíte. Aplikaci sestavíte tak, že v nabídce Sestavení kliknete na Sestavit řešení. Pokud se aplikace úspěšně sestaví, spusťte aplikaci kliknutím na Spustit ladění v nabídce Ladění .
[Nahoře]
Vytvoření třídy file_reader
Tato část ukazuje, jak vytvořit file_reader třídu. Modul runtime naplánuje, aby každý agent prováděl práci v vlastním kontextu. Proto můžete vytvořit agenta, který provádí synchronně práci, ale interaguje s ostatními komponentami asynchronně. Třída file_reader čte data z daného vstupního souboru a odesílá data z daného souboru do dané cílové komponenty.
Vytvoření třídy file_reader
Přidejte do projektu nový soubor hlaviček jazyka C++. Uděláte to tak, že v Průzkumník řešení kliknete pravým tlačítkem myši na uzel Soubory záhlaví, kliknete na Přidat a potom kliknete na Tlačítko Nová položka. V podokně Šablony vyberte Soubor záhlaví (.h). V dialogovém okně Přidat novou položku zadejte
file_reader.hdo pole Název a klepněte na tlačítko Přidat.Do file_reader.h přidejte následující kód.
#pragma onceV file_reader.h vytvořte třídu s názvem
file_reader, která je odvozena odagent.class file_reader : public concurrency::agent { public: protected: private: };Do oddílu předmětu
privatepřidejte následující datové členy.std::string _file_name; concurrency::ITarget<std::string>& _target; concurrency::overwrite_buffer<std::exception> _error;Člen
_file_nameje název souboru, ze kterého agent čte. Člen_targetje souběžnost::ITarget objekt, do kterého agent zapíše obsah souboru. Člen_errorobsahuje všechny chyby, ke kterým dochází během životnosti agenta.Do části
file_readertřídy přidejte následující kód propublickonstruktoryfile_reader.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í konstruktoru
file_readernastaví datové členy. Druhé a třetí přetížení konstruktoru umožňuje vaší aplikaci používat konkrétní plánovač s vaším agentem. První přetížení používá výchozí plánovač s vaším agentem.Přidejte metodu
get_errordo veřejné částifile_readertřídy.bool get_error(std::exception& e) { return try_receive(_error, e); }Metoda
get_errornačte všechny chyby, ke kterým dochází během životnosti agenta.Implementujte metodu concurrency::agent::run v
protectedčásti 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(); }
Metoda run otevře soubor a načte z něj data. Metoda run používá zpracování výjimek k zachycení všech chyb, ke kterým dochází během zpracování souboru.
Pokaždé, když tato metoda načte data ze souboru, volá funkci concurrency::asend , která tato data odešle do cílové vyrovnávací paměti. Odešle prázdný řetězec do cílové vyrovnávací paměti, aby indikovala konec zpracování.
Následující příklad ukazuje úplný 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žití třídy file_reader v aplikaci
Tato část ukazuje, jak pomocí file_reader třídy číst obsah textového souboru. Ukazuje také, jak vytvořit objekt concurrency::call , který přijímá data tohoto souboru a vypočítá jeho kontrolní součet Adler-32.
Použití třídy file_reader v aplikaci
Do BasicAgent.cpp přidejte následující
#includepříkaz.#include "file_reader.h"Do BasicAgent.cpp přidejte následující
usingdirektivy.using namespace concurrency; using namespace std;_tmainVe funkci vytvořte objekt concurrency::event, který signalizuje ukončení zpracování.event e;Vytvořte
callobjekt, který aktualizuje kontrolní součet při příjmu dat.// 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; }); });Tento
callobjekt také nastavíeventobjekt, když obdrží prázdný řetězec, aby signalizoval konec zpracování.Vytvořte
file_readerobjekt, který čte ze souboru test.txt a zapíše obsah tohoto souboru do objektucall.file_reader reader("test.txt", calculate_checksum);Spusťte agenta a počkejte, až se dokončí.
reader.start(); agent::wait(&reader);Počkejte,
callaž objekt přijme všechna data a dokončí se.e.wait();Zkontrolujte chyby v čtečce souborů. Pokud nedošlo k žádné chybě, vypočítejte konečný součet Adler-32 a vytiskněte 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 úplný soubor BasicAgent.cpp.
// 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;
}
}
[Nahoře]
Ukázkový vstup
Toto je ukázkový obsah vstupního souboru text.txt:
The quick brown fox
jumps
over the lazy dog
Ukázkový výstup
Při použití s ukázkovým vstupem vytvoří tento program následující výstup:
Adler-32 sum is fefb0d75
Robustní programování
Pokud chcete zabránit souběžnému přístupu k datovým členům, doporučujeme přidat metody, které provádějí práci do protectedprivate oddílu třídy. Do oddílu třídy přidejte metody, které odesílají nebo přijímají zprávy do nebo z agenta public .
Vždy volejte metodu concurrency::agent::d one a přesuňte agenta do dokončeného stavu. Tuto metodu obvykle voláte před návratem run z metody.
Další kroky
Další příklad aplikace založené na agentech naleznete v části Návod: Použití spojení k zabránění vzájemnému zablokování.
Viz také
Knihovna asynchronních agentů
Asynchronní bloky zpráv
Funkce pro předávání zpráv
Synchronizační datové struktury
Návod: Použití metody join k zabránění vzájemnému zablokování