Panduan: Membuat Aplikasi Berbasis Agen
Topik ini menjelaskan cara membuat aplikasi berbasis agen dasar. Dalam panduan ini, Anda dapat membuat agen yang membaca data dari file teks secara asinkron. Aplikasi ini menggunakan algoritma checksum Adler-32 untuk menghitung checksum konten file tersebut.
Prasyarat
Anda harus memahami topik berikut untuk menyelesaikan panduan ini:
Bagian
Panduan ini menunjukkan cara melakukan tugas berikut:
Membuat Aplikasi Konsol
Bagian ini menunjukkan cara membuat aplikasi konsol C++ yang mereferensikan file header yang akan digunakan program. Langkah-langkah awal bervariasi tergantung pada versi Visual Studio mana yang Anda gunakan. Untuk melihat dokumentasi untuk versi Visual Studio pilihan Anda, gunakan kontrol pemilih Versi. Kontrol tersebut dapat ditemukan di bagian atas daftar isi pada halaman ini.
Untuk membuat aplikasi konsol C++ di Visual Studio
Dari menu utama, pilih File>Baru>Proyek untuk membuka kotak dialog Buat Proyek Baru.
Di bagian atas dialog, atur Bahasa ke C++, atur Platform ke Windows, dan atur jenis Project ke Konsol.
Dari daftar jenis proyek yang difilter, pilih Aplikasi Konsol lalu pilih Berikutnya. Di halaman berikutnya, masukkan
BasicAgent
sebagai nama untuk proyek, dan tentukan lokasi proyek jika diinginkan.Pilih tombol Buat untuk membuat proyek.
Klik kanan simpul proyek di Penjelajah Solusi, dan pilih Properti. Di bawah Properti>Konfigurasi C/C++>Header>yang Telah Dikompilasi sebelumnya, pilih Buat.
Untuk membuat aplikasi konsol C++ di Visual Studio 2017 dan yang lebih lama
Pada menu File , klik Baru, lalu klik Proyek untuk menampilkan kotak dialog Proyek Baru.
Dalam kotak dialog Proyek Baru, pilih simpul Visual C++ di panel Jenis proyek lalu pilih Aplikasi Konsol Win32 di panel Templat. Ketik nama untuk proyek, misalnya,
BasicAgent
, lalu klik OK untuk menampilkan Panduan Aplikasi Konsol Win32.Dalam kotak dialog Panduan Aplikasi Konsol Win32, klik Selesai.
Memperbarui file header
Dalam file pch.h (stdafx.h di Visual Studio 2017 dan yang lebih lama), tambahkan kode berikut:
#include <agents.h>
#include <string>
#include <iostream>
#include <algorithm>
File header agents.h berisi fungsionalitas kelas konkurensi::agent .
Memverifikasi aplikasi
Terakhir, verifikasi bahwa aplikasi berhasil dibuat dengan membangun dan menjalankannya. Untuk membuat aplikasi, pada menu Build , klik Bangun Solusi. Jika aplikasi berhasil dibangun, jalankan aplikasi dengan mengklik Mulai Penelusuran Kesalahan pada menu Debug .
[Atas]
Membuat Kelas file_reader
Bagian ini menunjukkan cara membuat file_reader
kelas. Runtime menjadwalkan setiap agen untuk melakukan pekerjaan dalam konteksnya sendiri. Oleh karena itu, Anda dapat membuat agen yang melakukan pekerjaan secara sinkron, tetapi berinteraksi dengan komponen lain secara asinkron. Kelas membaca data dari file input tertentu dan mengirim data dari file tersebut file_reader
ke komponen target tertentu.
Untuk membuat kelas file_reader
Tambahkan file header C++ baru ke proyek Anda. Untuk melakukannya, klik kanan simpul File Header di Penjelajah Solusi, klik Tambahkan, lalu klik Item Baru. Di panel Templat, pilih File Header (.h). Dalam kotak dialog Tambahkan Item Baru, ketik
file_reader.h
di kotak Nama lalu klik Tambahkan.Di file_reader.h, tambahkan kode berikut.
#pragma once
Di file_reader.h, buat kelas yang diberi nama
file_reader
yang berasal dariagent
.class file_reader : public concurrency::agent { public: protected: private: };
Tambahkan anggota data berikut ke bagian
private
kelas Anda.std::string _file_name; concurrency::ITarget<std::string>& _target; concurrency::overwrite_buffer<std::exception> _error;
Anggota
_file_name
adalah nama file yang dibaca agen. Anggota_target
adalah objek konkurensi::ITarget tempat agen menulis konten file. Anggota_error
menyimpan kesalahan apa pun yang terjadi selama masa pakai agen.Tambahkan kode berikut untuk
file_reader
konstruktor ke bagianpublic
file_reader
kelas.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) { }
Setiap kelebihan beban konstruktor mengatur
file_reader
anggota data. Kelebihan beban konstruktor kedua dan ketiga memungkinkan aplikasi Anda menggunakan penjadwal tertentu dengan agen Anda. Kelebihan beban pertama menggunakan penjadwal default dengan agen Anda.get_error
Tambahkan metode ke bagian publik kelasfile_reader
.bool get_error(std::exception& e) { return try_receive(_error, e); }
Metode ini
get_error
mengambil kesalahan apa pun yang terjadi selama masa pakai agen.Terapkan metode konkurensi::agent::run di bagian
protected
kelas Anda.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(); }
Metode run
ini membuka file dan membaca data darinya. Metode ini run
menggunakan penanganan pengecualian untuk menangkap kesalahan apa pun yang terjadi selama pemrosesan file.
Setiap kali metode ini membaca data dari file, metode ini memanggil fungsi konkurensi::asend untuk mengirim data tersebut ke buffer target. Ini mengirimkan string kosong ke buffer targetnya untuk menunjukkan akhir pemrosesan.
Contoh berikut menunjukkan konten lengkap 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;
};
[Atas]
Menggunakan Kelas file_reader di Aplikasi
Bagian ini memperlihatkan cara menggunakan file_reader
kelas untuk membaca konten file teks. Ini juga menunjukkan cara membuat objek konkurensi::panggilan yang menerima data file ini dan menghitung checksum Adler-32-nya.
Untuk menggunakan kelas file_reader di aplikasi Anda
Di BasicAgent.cpp, tambahkan pernyataan berikut
#include
.#include "file_reader.h"
Di BasicAgent.cpp, tambahkan arahan berikut
using
.using namespace concurrency; using namespace std;
_tmain
Dalam fungsi , buat konkurensi::objek peristiwa yang menandakan akhir pemrosesan.event e;
Buat
call
objek yang memperbarui checksum saat menerima 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; }); });
Objek ini
call
juga mengaturevent
objek ketika menerima string kosong untuk memberi sinyal akhir pemrosesan.Buat
file_reader
objek yang membaca dari file test.txt dan menulis konten file tersebut kecall
objek.file_reader reader("test.txt", calculate_checksum);
Mulai agen dan tunggu hingga selesai.
reader.start(); agent::wait(&reader);
Tunggu
call
hingga objek menerima semua data dan selesai.e.wait();
Periksa pembaca file untuk kesalahan. Jika tidak ada kesalahan yang terjadi, hitung jumlah Adler-32 akhir dan cetak jumlah ke konsol.
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; }
Contoh berikut menunjukkan file BasicAgent.cpp lengkap.
// 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;
}
}
[Atas]
Input Sampel
Ini adalah contoh konten file input text.txt:
The quick brown fox
jumps
over the lazy dog
Output sampel
Ketika digunakan dengan input sampel, program ini menghasilkan output berikut:
Adler-32 sum is fefb0d75
Pemrograman yang Kuat
Untuk mencegah akses bersamaan ke anggota data, kami sarankan Anda menambahkan metode yang melakukan pekerjaan ke protected
bagian atau private
kelas Anda. Hanya tambahkan metode yang mengirim atau menerima pesan ke atau dari agen ke bagian public
kelas Anda.
Selalu panggil metode concurrency::agent::d one untuk memindahkan agen Anda ke status selesai. Anda biasanya memanggil metode ini sebelum anda kembali dari run
metode .
Langkah berikutnya
Untuk contoh lain aplikasi berbasis agen, lihat Panduan: Menggunakan gabungan untuk Mencegah Kebuntuan.
Baca juga
Pustaka Agen Asinkron
Blok Pesan Asinkron
Fungsi Passing Pesan
Struktur Data Sinkronisasi
Panduan: Menggunakan gabungan untuk Mencegah Kebuntuan
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk