Aracılığıyla paylaş


Çok İş Parçacıklı Direct2D Uygulamaları

Direct2D uygulamaları geliştirirseniz, direct2D kaynaklarına birden fazla iş parçacığından erişmeniz gerekebilir. Diğer durumlarda, daha iyi performans veya daha iyi yanıt hızı elde etmek için çok iş parçacığı kullanmak isteyebilirsiniz (örneğin, ekran görüntüsü için bir iş parçacığı ve çevrimdışı işleme için ayrı bir iş parçacığı kullanma).

Bu konu başlığında, çok iş parçacıklı Direct2D uygulamalarını çok az Direct3D işleme ile geliştirmeye yönelik en iyi yöntemler açıklanmaktadır. Eşzamanlılık sorunlarının neden olduğu yazılım hatalarını izlemek zor olabilir ve çoklu iş parçacığı ilkenizi planlamak ve burada açıklanan en iyi yöntemleri izlemek yararlı olabilir.

Not

İki farklı iş parçacıklı Direct2D fabrikasından oluşturulan iki Direct2D kaynağına erişiyorsanız, temel Direct3D cihazları ve cihaz bağlamları da ayrı olduğu sürece erişim çakışmalarına neden olmaz. Bu makaledeki "Direct2D kaynaklarına erişme" hakkında konuşurken, aksi belirtilmedikçe "aynı Direct2D Cihazından oluşturulan Direct2D kaynaklarına erişme" anlamına gelir.

Yalnızca Direct2D API'lerini Çağıran Thread-Safe Uygulamaları Geliştirme

Çok iş parçacıklı Direct2D fabrika örneği oluşturabilirsiniz. Birden fazla iş parçacığından çok iş parçacıklı bir fabrikayı ve tüm kaynaklarını kullanabilir ve paylaşabilirsiniz, ancak bu kaynaklara erişimler (Direct2D çağrıları aracılığıyla) Direct2D tarafından serileştirilir, bu nedenle erişim çakışması olmaz. Uygulamanız yalnızca Direct2D API'lerini çağırırsa, bu koruma Direct2D tarafından otomatik olarak minimum ek yükle ayrıntılı bir düzeyde yapılır. Burada çok iş parçacıklı fabrika oluşturma kodu.

ID2D1Factory* m_D2DFactory;

// Create a Direct2D factory.
HRESULT hr = D2D1CreateFactory(
    D2D1_FACTORY_TYPE_MULTI_THREADED,
    &m_D2DFactory
);

Buradaki görüntüde Direct2D'ın yalnızca Direct2D API'sini kullanarak çağrı yapacak iki iş parçacığını nasıl serileştirdiğini gösterir.

iki serileştirilmiş iş parçacığı diyagramı.

En az Direct3D veya DXGI Çağrılarıyla Thread-Safe Direct2D Uygulamaları Geliştirme

Bir Direct2D uygulamasının da direct3D veya DXGI çağrıları çoğu zaman vardır. Örneğin, bir görüntü iş parçacığı Direct2D'de çizilecek ve DXGI takas zincirikullanılarak sunulacaktır.

Bu durumda, iş parçacığı güvenliğini sağlama daha karmaşıktır: bazı Direct2D çağrıları, Direct3D veya DXGI çağıran başka bir iş parçacığı tarafından aynı anda erişilebilen temel Direct3D kaynaklarına dolaylı olarak erişiyor. Bu Direct3D veya DXGI çağrıları Direct2D'nin farkındalığı ve denetimi dışında olduğundan, çok iş parçacıklı bir Direct2D fabrikası oluşturmanız gerekir, ancak erişim çakışmalarını önlemek için gerekli işlemleri yapmanız gerekir.

Buradaki diyagramda, Direct3D kaynak erişimi çakışması, iş parçacığı T0'ın Direct2D çağrısı aracılığıyla dolaylı olarak bir kaynağa erişmesi ve T2'nin doğrudan Direct3D veya DXGI çağrısı aracılığıyla aynı kaynağa erişmesi nedeniyle ortaya çıkar.

Not

Direct2D iş parçacığı koruması (bu görüntüdeki mavi kilit) bu durumda yardımcı olmaz.

 

İş parçacığı koruma diyagramını .

Burada kaynak erişimi çakışmasını önlemek için, Direct2D iç erişim eşitlemesi için kullandığı kilidi açıkça edinmenizi ve burada gösterildiği gibi bir iş parçacığının Direct3D veya DXGI çağrıları yapması gerektiğinde bu kilidi uygulamanızı öneririz. Özellikle, özel durumlar kullanan kodlarla veya HRESULT dönüş kodlarını temel alan erken çıkan bir sistemle özel olarak ilgilenmeniz gerekir. Bu nedenle, Enter çağırmak ve bırak yöntemlerini çağırmak için BIR RAII (Kaynak Alımı Başlatılıyor) deseni kullanmanızı öneririz.

Not

Enter ve yöntemleri bırakın çağrılarını eşleştirmeniz önemlidir; aksi takdirde uygulamanız kilitlenmeye neden olabilir.

 

Buradaki kod, Direct3D veya DXGI çağrıları kilitlenip kilidinin ne zaman açıldığını gösteren bir örnek gösterir.

void MyApp::DrawFromThread2()
{
    // We are accessing Direct3D resources directly without Direct2D's knowledge, so we
    // must manually acquire and apply the Direct2D factory lock.
    ID2D1Multithread* m_D2DMultithread;
    m_D2DFactory->QueryInterface(IID_PPV_ARGS(&m_D2DMultithread));
    m_D2DMultithread->Enter();
    
    // Now it is safe to make Direct3D/DXGI calls, such as IDXGISwapChain::Present
    MakeDirect3DCalls();

    // It is absolutely critical that the factory lock be released upon
    // exiting this function, or else any consequent Direct2D calls will be blocked.
    m_D2DMultithread->Leave();
}

Not

Bazı Direct3D veya DXGI çağrıları (özellikle IDXGISwapChain::P resent), çağrı işlevinin veya yönteminin koduna kilitler ve/veya geri çağırmaları tetikleyebilir. Bunun farkında olmanız ve bu tür davranışların kilitlenmelere neden olmadığından emin olmanız gerekir. Daha fazla bilgi için DXGI'ya Genel Bakış konusuna bakın.

 

direct2d ve direct3d iş parçacığı kilitleme diyagramını .

Enter ve Leave yöntemlerini kullandığınızda, çağrılar otomatik Direct2D ve açık kilit tarafından korunur, böylece uygulama erişim çakışmasını yakalamaz.

Bu sorunu geçici olarak çözmek için başka yaklaşımlar da vardır. Ancak Direct3D veya DXGI çağrılarını Direct2D kilidiyle açıkça korumanızı öneririz çünkü direct2D'nin kapağı altında eşzamanlılığı çok daha ince bir düzeyde ve daha düşük ek yükle koruduğundan genellikle daha iyi performans sağlar.

Durum Bilgisi Olan İşlemlerin Bölünmezliğini Sağlama

DirectX iş parçacığı güvenliği özellikleri, aynı anda iki ayrı API çağrısı yapılmamasını sağlamaya yardımcı olsa da, durum bilgisi olan API çağrıları yapan iş parçacıklarının birbiriyle karışmadığından da emin olmanız gerekir. Aşağıda bir örnek verilmiştir.

  1. Hem ekranda (İş Parçacığı 0'a göre) hem de ekran dışında (İş Parçacığı 1'e göre) işlemek istediğiniz iki metin satırı vardır: 1. Satır "A büyüktür" ve Satır #2 "B'den büyüktür", her ikisi de düz siyah fırça kullanılarak çizilir.
  2. yazışma 1 metnin ilk satırını çizer.
  3. İş parçacığı 0 bir kullanıcı girişine tepki verir, hem metin çizgilerini sırasıyla "B daha küçük" hem de "A'dan" olarak güncelleştirir ve fırça rengini kendi çizimi için düz kırmızı olarak değiştirir;
  4. Yazışma 1, kırmızı renk fırçasıyla artık "A'dan" daha büyük ikinci metin satırını çizmeye devam eder;
  5. Son olarak, ekran dışı çizim hedefinde iki satırlık metin elde ediyoruz: siyah "A büyüktür", kırmızı "A'dan büyüktür".

Açık ve kapalı ekran iş parçacıklarının diyagramını .

Üst satırda, İş Parçacığı 0 geçerli metin dizeleri ve geçerli siyah fırça ile çizer. İş parçacığı 1 yalnızca üst yarıdaki ekran dışı çizimi tamamlar.

Orta satırda, İş Parçacığı 0 kullanıcı etkileşimine yanıt verir, metin dizelerini ve fırçayı güncelleştirir, ardından ekranı yeniler. Bu noktada İş Parçacığı 1 engellenir. Alt satırda, İş Parçacığı 1'in ardından son ekran dışı işleme, alt yarısını değiştirilmiş bir fırça ve değiştirilmiş bir metin dizesiyle çizmeye devam eder.

Bu sorunu gidermek için her iş parçacığı için ayrı bir bağlama sahip olmanız önerilir, böylece:

  • Değişken kaynakların (örneğin, metin içeriği veya örnekteki düz renk fırçası gibi görüntüleme veya yazdırma sırasında farklılık gösterebilen kaynaklar) işlendiğinde değişmemesi için cihaz bağlamının bir kopyasını oluşturmanız gerekir. Bu örnekte, çizmeden önce bu iki metin satırı ve renk fırçasının bir kopyasını tutmalısınız. Bunu yaparak, her iş parçacığının çizip sunmak için eksiksiz ve tutarlı içeriğe sahip olmasını garantilersiniz.
  • Bir kez başlatılan ve ardından performansı artırmak için iş parçacıkları arasında hiç değiştirilmemiş ağır kaynakları (bit eşlemler ve karmaşık efekt grafikleri gibi) paylaşmanız gerekir.
  • Bir kez başlatılan ve ardından iş parçacıkları arasında hiç değiştirilmeyen hafif kaynakları (düz renk fırçaları ve metin biçimleri gibi) paylaşabilirsiniz

Özet

Çok iş parçacıklı Direct2D uygulamaları geliştirirken, çok iş parçacıklı bir Direct2D fabrikası oluşturmanız ve ardından tüm Direct2D kaynaklarını bu fabrikadan türetmelisiniz. bir iş parçacığı Direct3D veya DXGI çağrıları yapacaksa, bu Direct3D veya DXGI çağrılarını korumak için Direct2D kilidini de açıkça almanız gerekir. Ayrıca, her iş parçacığı için değiştirilebilir kaynakların bir kopyasına sahip olarak bağlam bütünlüğünü sağlamanız gerekir.