Aracılığıyla paylaş


İzlenecek Yol: Aracı Temelli Uygulama Oluşturma

Bu konu başlığında, temel aracı tabanlı bir uygulamanın nasıl oluşturulacağı açıklanmaktadır. Bu kılavuzda, bir metin dosyasındaki verileri zaman uyumsuz olarak okuyan bir aracı oluşturabilirsiniz. Uygulama, söz konusu dosyanın içeriğinin sağlama toplamını hesaplamak için Adler-32 sağlama toplamı algoritmasını kullanır.

Ön koşullar

Bu kılavuzu tamamlamak için aşağıdaki konuları anlamanız gerekir:

Bölümler

Bu kılavuzda aşağıdaki görevlerin nasıl gerçekleştirebileceğiniz gösterilmektedir:

Konsol Uygulaması Oluşturma

Bu bölümde, programın kullanacağı üst bilgi dosyalarına başvuran bir C++ konsol uygulamasının nasıl oluşturulacağı gösterilmektedir. İlk adımlar, hangi Visual Studio sürümünü kullandığınıza bağlı olarak değişir. Tercih ettiğiniz Visual Studio sürümünün belgelerini görmek için Sürüm seçici denetimini kullanın. Bu sayfadaki içindekiler tablosunun en üstünde bulunur.

Visual Studio'da C++ konsol uygulaması oluşturmak için

  1. Ana menüden Dosya>Yeni Proje'yi seçerek Yeni>Proje Oluştur iletişim kutusunu açın.

  2. İletişim kutusunun üst kısmında Dil'i C++ olarak, Platform'ı Windows olarak ve Proje türü'nü Konsol olarak ayarlayın.

  3. Filtrelenen proje türleri listesinden Konsol Uygulaması'nı ve ardından İleri'yi seçin. Sonraki sayfada, projenin adı olarak girin BasicAgent ve isterseniz proje konumunu belirtin.

  4. Projeyi oluşturmak için Oluştur düğmesini seçin.

  5. Çözüm Gezgini proje düğümüne sağ tıklayın ve Özellikler'i seçin. Yapılandırma Özellikleri>C/C++>Önceden Derlenmiş Üst Bilgiler>Önceden Derlenmiş üst bilgi altında Oluştur'u seçin.

Visual Studio 2017 ve önceki sürümlerde C++ konsol uygulaması oluşturmak için

  1. Dosya menüsünde Yeni'ye tıklayın ve ardından Yeni Proje iletişim kutusunu görüntülemek için Proje'ye tıklayın.

  2. Yeni Proje iletişim kutusunda, Proje türleri bölmesinde Visual C++ düğümünü seçin ve ardından Şablonlar bölmesinde Win32 Konsol Uygulaması'nıseçin. Proje için örneğin, BasicAgentbir ad yazın ve Win32 Konsol Uygulaması Sihirbazı'nı görüntülemek için Tamam'a tıklayın.

  3. Win32 Konsol Uygulaması Sihirbazı iletişim kutusunda Son'a tıklayın.

Üst bilgi dosyasını güncelleştirme

pch.h (Visual Studio 2017 ve önceki sürümlerde stdafx.h) dosyasına aşağıdaki kodu ekleyin:

#include <agents.h>
#include <string>
#include <iostream>
#include <algorithm>

agents.h üst bilgisi, concurrency::agent sınıfının işlevselliğini içerir.

Uygulamayı doğrulama

Son olarak, uygulamanın oluşturup çalıştırarak başarıyla oluşturulduğunu doğrulayın. Uygulamayı derlemek için, Derleme menüsünde Çözüm Oluştur'a tıklayın. Uygulama başarıyla derleniyorsa, Hata Ayıklama menüsünde Hata Ayıklamayı Başlat'a tıklayarak uygulamayı çalıştırın.

[Üst]

file_reader Sınıfı Oluşturma

Bu bölümde sınıfın nasıl oluşturulacağı gösterilmektedir file_reader . Çalışma zamanı, her aracıyı kendi bağlamında iş gerçekleştirmek üzere zamanlar. Bu nedenle, zaman uyumlu bir şekilde iş gerçekleştiren ancak diğer bileşenlerle zaman uyumsuz olarak etkileşim kuran bir aracı oluşturabilirsiniz. sınıfı, file_reader belirli bir giriş dosyasındaki verileri okur ve bu dosyadan belirli bir hedef bileşene veri gönderir.

File_reader sınıfını oluşturmak için

  1. Projenize yeni bir C++ üst bilgi dosyası ekleyin. Bunu yapmak için, Çözüm Gezgini Üst Bilgi Dosyaları düğümüne sağ tıklayın, Ekle'ye ve ardından Yeni Öğe'ye tıklayın. Şablonlar bölmesinde Üst Bilgi Dosyası (.h) öğesini seçin. Yeni Öğe Ekle iletişim kutusunda, Ad kutusuna yazın file_reader.h ve Ekle'ye tıklayın.

  2. file_reader.h dosyasında aşağıdaki kodu ekleyin.

    #pragma once
    
  3. file_reader.h dosyasından agenttüretilen adlı file_reader bir sınıf oluşturun.

    class file_reader : public concurrency::agent
    {
    public:
    protected:
    private:
    };
    
  4. Aşağıdaki veri üyelerini private sınıfınızın bölümüne ekleyin.

    std::string _file_name;
    concurrency::ITarget<std::string>& _target;
    concurrency::overwrite_buffer<std::exception> _error;
    

    Üye _file_name , aracının okuduğu dosya adıdır. Üye _target , aracının dosyanın içeriğini yazdığı eşzamanlılık ::ITarget nesnesidir. Üye, _error aracının ömrü boyunca oluşan herhangi bir hatayı tutar.

  5. Oluşturucular için file_reader aşağıdaki kodu sınıfın publicfile_reader bölümüne ekleyin.

    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)
    {
    }
    

    Her oluşturucu aşırı yüklemesi veri üyelerini file_reader ayarlar. İkinci ve üçüncü oluşturucu aşırı yüklemesi, uygulamanızın aracınızla belirli bir zamanlayıcı kullanmasını sağlar. İlk aşırı yükleme aracınızla varsayılan zamanlayıcıyı kullanır.

  6. get_error yöntemini sınıfın genel bölümüne file_reader ekleyin.

    bool get_error(std::exception& e)
    {
       return try_receive(_error, e);
    }
    

    yöntemi, get_error aracının ömrü boyunca oluşan tüm hataları alır.

  7. Sınıfınızın bölümünde concurrency::agent::run yöntemini protected uygulayın.

    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 yöntemi dosyayı açar ve ondan verileri okur. yöntemi, run dosya işleme sırasında oluşan hataları yakalamak için özel durum işlemeyi kullanır.

Bu yöntem dosyadaki verileri her okuduğunda, bu verileri hedef arabelleğe göndermek için eşzamanlılık::asend işlevini çağırır. İşlem sonunu belirtmek için boş dizeyi hedef arabelleğine gönderir.

Aşağıdaki örnekte file_reader.h dosyasının tüm içeriği gösterilmektedir.

#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;
};

[Üst]

Uygulamadaki file_reader Sınıfını Kullanma

Bu bölümde, bir metin dosyasının file_reader içeriğini okumak için sınıfın nasıl kullanılacağı gösterilmektedir. Ayrıca bu dosya verilerini alan ve Adler-32 sağlama toplamını hesaplayan concurrency ::call nesnesinin nasıl oluşturulacağını da gösterir.

File_reader sınıfını Uygulamanızda kullanmak için

  1. BasicAgent.cpp dosyasında aşağıdaki #include deyimi ekleyin.

    #include "file_reader.h"
    
  2. BasicAgent.cpp dosyasında aşağıdaki using yönergeleri ekleyin.

    using namespace concurrency;
    using namespace std;
    
  3. işlevinde _tmain , işlemenin sona erdiğini belirten bir concurrency::event nesnesi oluşturun.

    event e;
    
  4. Veri aldığında sağlama toplamını güncelleştiren bir call nesne oluşturun.

    // 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;
       });
    });
    

    Bu call nesne, boş dizeyi aldığında da işlemenin sonuna işaret etmek için nesnesini ayarlar event .

  5. test.txt dosyasından okuyan ve bu dosyanın içeriğini nesneye call yazan bir file_reader nesne oluşturun.

    file_reader reader("test.txt", calculate_checksum);
    
  6. Aracıyı başlatın ve bitmesini bekleyin.

    reader.start();
    agent::wait(&reader);
    
  7. Nesnenin call tüm verileri almasını ve tamamlanmasını bekleyin.

    e.wait();
    
  8. Dosya okuyucuda hatalar olup olmadığını denetleyin. Hata oluşmadıysa, son Adler-32 toplamını hesaplayın ve toplamı konsola yazdırın.

    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;
    }
    

Aşağıdaki örnekte BasicAgent.cpp dosyasının tamamı gösterilmektedir.

// 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;
   }
}

[Üst]

Örnek Giriş

Bu, text.txt giriş dosyasının örnek içeriğidir:

The quick brown fox
jumps
over the lazy dog

Örnek Çıkış

Örnek girişle kullanıldığında, bu program aşağıdaki çıkışı üretir:

Adler-32 sum is fefb0d75

Güçlü Programlama

Veri üyelerine eşzamanlı erişimi önlemek için, sınıfınızın veya private bölümüne iş protected gerçekleştiren yöntemler eklemenizi öneririz. Yalnızca aracıya veya aracıdan public ileti gönderen veya alan yöntemleri sınıfınızın bölümüne ekleyin.

Aracınızı tamamlanmış duruma taşımak için her zaman concurrency::agent::d one yöntemini çağırın. Yönteminden run dönmeden önce genellikle bu yöntemi çağırırsınız.

Sonraki Adımlar

Aracı tabanlı bir uygulamanın başka bir örneği için bkz . İzlenecek yol: Kilitlenmeyi Önlemek için birleştirmeyi kullanma.

Ayrıca bkz.

Zaman Uyumsuz Aracılar Kitaplığı
Zaman Uyumsuz İleti Blokları
İleti Geçirme İşlevleri
Eşitleme Veri Yapıları
İzlenecek Yol: Kilitlenmeyi Önlemek için birleştirme kullanma