Aracılığıyla paylaş


Nasıl yapılır: işbirlikçi bir semafor uygulamak için içerik sınıfını kullanın

Bu konuda nasıl kullanılacağını gösterir concurrency::Context işbirlikçi semafor sınıfı uygulamak için sınıf.

Context Sınıfı, engellemek veya geçerli yürütme içeriği verim sağlar.Geçerli içerik bir kaynağın kullanılabilir olmadığı için devam edemiyor engelleme veya geçerli içerik istediðinde yararlıdır.A Semafor burada geçerli yürütme içeriği beklemesi gereken bir kaynak kullanılabilir olana kadar tek bir durum örneğidir.Kritik bölüm nesnesi gibi bir semafor kodda bir kaynak için özel kullanım erişimine sahip bir içerik sağlayan bir eşitleme nesnesidir.Ancak, kritik bölüm nesnesi, bir semafor kaynağa aynı anda erişmek birden fazla içerik sağlar.Semafor kilit sayısının içerikleri tutuyorsa, her ek içerik kilidi açmak başka bir içerik için beklemeniz gerekir.

Semafor sınıfı uygulamak için

  1. Adlı bir sınıf bildirmek semaphore.Add public ve private bu sınıfa bölümler.

    // A semaphore type that uses cooperative blocking semantics.
    class semaphore
    {
    public:
    private:
    };
    
  2. De private bölümünü semaphore sınıfı, bildirdiğiniz bir std::atomic semafor sayısı tutan değişken ve bir concurrency::concurrent_queue semafor almak için beklemesi gereken içerikleri tutan nesne.

    // The semaphore count.
    atomic<long long> _semaphore_count;
    
    // A concurrency-safe queue of contexts that must wait to 
    // acquire the semaphore.
    concurrent_queue<Context*> _waiting_contexts;
    
  3. De public bölümünü semaphore sınıfı, kurucu uygulamak.Kurucu götüren bir long long aynı anda kilit tutan bağlamları maksimum sayısını belirten değer.

    explicit semaphore(long long capacity)
       : _semaphore_count(capacity)
    {
    }
    
  4. De public bölümünü semaphore sınıfı, uygulayan acquire yöntemi.Bu yöntem azaltır semafor Atomik işlem olarak sayılır.Semafor Sayısı negatif hale gelirse, bu bağlamda bekleme sırası ve çağrı sonuna ekleyin concurrency::Context::Block geçerli içerik engelleme yöntemi.

    // Acquires access to the semaphore.
    void acquire()
    {
       // The capacity of the semaphore is exceeded when the semaphore count 
       // falls below zero. When this happens, add the current context to the 
       // back of the wait queue and block the current context.
       if (--_semaphore_count < 0)
       {
          _waiting_contexts.push(Context::CurrentContext());
          Context::Block();
       }
    }
    
  5. De public bölümünü semaphore sınıfı, uygulayan release yöntemi.Bu yöntem, Atomik işlem olarak semafor sayısı değerini artırır.Semafor Sayısı artış operasyondan önce negatif ise, kilit için bekleyen en az bir içerik yoktur.Bu durumda bekleme sırası öne olan içeriği engellemeyi kaldır.

    // Releases access to the semaphore.
    void release()
    {
       // If the semaphore count is negative, unblock the first waiting context.
       if (++_semaphore_count <= 0)
       {
          // A call to acquire might have decremented the counter, but has not
          // yet finished adding the context to the queue. 
          // Create a spin loop that waits for the context to become available.
          Context* waiting = NULL;
          while (!_waiting_contexts.try_pop(waiting))
          {
             Context::Yield();
          }
    
          // Unblock the context.
          waiting->Unblock();
       }
    }
    

Örnek

semaphore Bu örnekteki sınıfın davrandığını cooperatively çünkü Context::Block ve Context::Yield yöntemleri verim yürütülmesine böylece çalışma zamanı başka görevler gerçekleştirebilir.

acquire Sayacı, ancak değil son bekleme sırası başka bir içerik aramaları önce içerik ekleme yöntemi azaltır release yöntemi.Bunun için hesap için release yöntemini çağıran bir dönüş döngü kullanır concurrency::Context::Yield beklemek için yöntem acquire içerik eklemeyi tamamlamak için yöntem.

release Yöntemini çağırabilir Context::Unblock yöntemi önce acquire yöntem çağrıları Context::Block yöntemi.Çalışma zamanı bu yöntemlerin herhangi bir sırada çağrılmasına izin verdiğinden bu yarış karşı korumak zorunda değildir.release Yöntem çağrıları Context::Unblock önce acquire yöntem çağrıları Context::Block aynı içerik için o içerik engellenmemiş kalır.Çalışma zamanı yalnızca her için aramayı gerektirir Context::Block karşılık gelen bir çağrı ile eşleşti Context::Unblock.

Aşağıdaki örnekte gösterilmektedir tam semaphore sınıfı.wmain İşlevi, bu sınıfın temel kullanımı gösterilmektedir.wmain İşlevini kullanan concurrency::parallel_for erişmesi gereken semaforu çeşitli görevler oluşturma algoritması.Bazı görevler, üç iş parçacıkları, herhangi bir anda kilit tutun çünkü bitirmek ve kilidi açmak başka bir görev için beklemeniz gerekir.

// cooperative-semaphore.cpp
// compile with: /EHsc
#include <atomic>
#include <concrt.h>
#include <ppl.h>
#include <concurrent_queue.h>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

// A semaphore type that uses cooperative blocking semantics.
class semaphore
{
public:
   explicit semaphore(long long capacity)
      : _semaphore_count(capacity)
   {
   }

   // Acquires access to the semaphore.
   void acquire()
   {
      // The capacity of the semaphore is exceeded when the semaphore count 
      // falls below zero. When this happens, add the current context to the 
      // back of the wait queue and block the current context.
      if (--_semaphore_count < 0)
      {
         _waiting_contexts.push(Context::CurrentContext());
         Context::Block();
      }
   }

   // Releases access to the semaphore.
   void release()
   {
      // If the semaphore count is negative, unblock the first waiting context.
      if (++_semaphore_count <= 0)
      {
         // A call to acquire might have decremented the counter, but has not
         // yet finished adding the context to the queue. 
         // Create a spin loop that waits for the context to become available.
         Context* waiting = NULL;
         while (!_waiting_contexts.try_pop(waiting))
         {
            Context::Yield();
         }

         // Unblock the context.
         waiting->Unblock();
      }
   }

private:
   // The semaphore count.
   atomic<long long> _semaphore_count;

   // A concurrency-safe queue of contexts that must wait to 
   // acquire the semaphore.
   concurrent_queue<Context*> _waiting_contexts;
};

int wmain()
{
   // Create a semaphore that allows at most three threads to 
   // hold the lock.
   semaphore s(3);

   parallel_for(0, 10, [&](int i) {
      // Acquire the lock.
      s.acquire();

      // Print a message to the console.
      wstringstream ss;
      ss << L"In loop iteration " << i << L"..." << endl;
      wcout << ss.str();

      // Simulate work by waiting for two seconds.
      wait(2000);

      // Release the lock.
      s.release();
   });
}

Bu örnek, aşağıdaki örnek çıktı oluşturur.

In loop iteration 5...
In loop iteration 0...
In loop iteration 6...
In loop iteration 1...
In loop iteration 2...
In loop iteration 7...
In loop iteration 3...
In loop iteration 8...
In loop iteration 9...
In loop iteration 4...

concurrent_queue sınıfı hakkında daha fazla bilgi için, bkz. Paralel kapsayıcıları ve nesneleri.Hakkında daha fazla bilgi için parallel_for , algoritması bkz: Paralel algoritmalar.

Kod Derleniyor

Örnek kodu kopyalayın ve Visual Studio Project'te yapıştırın ya da adlı bir dosyaya yapıştırın cooperative semaphore.cpp ve Visual Studio komut istemi penceresinde aşağıdaki komutu çalıştırın.

cl.exe /EHsc cooperative-semaphore.cpp

Güçlü Programlama

Kullanabileceğiniz Kaynak edinme ise başlatma (RAII) desen erişimi sınırlamak için bir semaphore belirli bir kapsam nesnesi.RAII düzeni altında yığında bir veri yapısı tahsis edilir.Bu veri yapısı başlatır veya oluşturulur ve bozar veya veri yapısı bozulduğunda bu kaynağı bırakır, kaynak isteklerdir.RAII desen kapsayan kapsam kapanması yıkıcı adlı güvence altına alır.Bu nedenle, kaynak düzgün bir özel durum veya birden fazla fonksiyon içeren yönetilen return deyimleri.

Aşağıdaki örnek adında bir sınıfı tanımlar scoped_lock, hangi tanımlanmış public bölümünü semaphore sınıfı.scoped_lock Class benzer concurrency::critical_section::scoped_lock ve concurrency::reader_writer_lock::scoped_lock sınıfları.Yapıcısı semaphore::scoped_lock sınıf isteklerdir erişim verilen semaphore nesnesi ve yıkıcı ilgili nesneye erişimi serbest bırakır.

// An exception-safe RAII wrapper for the semaphore class.
class scoped_lock
{
public:
   // Acquires access to the semaphore.
   scoped_lock(semaphore& s)
      : _s(s)
   {
      _s.acquire();
   }
   // Releases access to the semaphore.
   ~scoped_lock()
   {
      _s.release();
   }

private:
   semaphore& _s;
};

Aşağıdaki örnek için geçirilen iş işlev gövdesi değiştirir parallel_for algoritması, böylece o BT işlevini verir önce bir semafor serbest bırakılmasını sağlamak için RAII kullanır.Bu teknik çalışma işlevini özel durum-güvenli garanti eder.

parallel_for(0, 10, [&](int i) {
   // Create an exception-safe scoped_lock object that holds the lock 
   // for the duration of the current scope.
   semaphore::scoped_lock auto_lock(s);

   // Print a message to the console.
   wstringstream ss;
   ss << L"In loop iteration " << i << L"..." << endl;
   wcout << ss.str();

   // Simulate work by waiting for two seconds.
   wait(2000);
});

Ayrıca bkz.

Başvuru

İçerik sınıfı

Kavramlar

Bağlamları

Paralel kapsayıcıları ve nesneleri