2014-11-24 13 views
5

Aynı anda tam olarak bir açılır pencerenin görüntülenmesini sağlayan bir hizmetim var. . AddPopupAsync kodu başka bir 10 AddPopupAsync istekleri düşüş ise bir pop-up açıktır, yani aynı anda çağrılabilir:Kuyruk ipliği güvenliğini kullanan eşzamansız yöntemler nasıl yapılır

public async Task<int> AddPopupAsync(Message message) 
{ 
    //[...] 

    while (popupQueue.Count != 0) 
    { 
     await popupQueue.Peek(); 
    } 

    return await Popup(interaction); 
} 

Ama çünkü iplik güvenliği ait eksikliği ortaya çıkabilir iki istenmeyen şeyler nokta olabilir:

Sıra hala boş olduğundan
  1. sıra boş ise, Peek bir iplik A Popup birinci deyimin önüne kılınırsa Eğer bir istisna
  2. atacağım, başka bir iş parçacığı B bekleyen açılan A için beklemeyecek.

Popup yöntemi TaskCompletionSource ile çalışır ve onun SetResult yöntemini çağırmadan önce, popupQueue.Dequeue() denir.

do 
{ 
    Task<int> result; 

    bool success = popupQueue.TryPeek(out result); 

    if (!success) break; 
    await result; 
} 
while (true); 

Sonra bir AsyncProducerConsumerCollection okudum ama bu en basit çözüm olmadığından emin değilim:

Ben 1. parçacığı güvenli kılmak için ConcurrentQueue atom TryPeek kullanma hakkında düşünüyorum.

İplik güvenliğini basit bir şekilde nasıl sağlayabilirim? Teşekkür ederim.

+1

Sanırım kendi sorunuzu cevapladınız. ConcurrentQueue ', ihtiyacınız olan her şeye sahiptir. –

+0

Geçerli semantik iseniz, tüm pop-up'lar görüntülenene kadar '' AddPopupAsync'' için yapılan tüm çağrılar tamamlanmayacaktır (sadece belirli bir aramanın gösterdiği gibi). İstediğiniz semantiğin bu olduğuna emin misin? –

+0

@Stephen Cleary PopupView ve PopupViewModel tekil olduktan sonra, Popup çağrıldığında, kalıcı pop-up penceresinin durumu değişir. Ve bu yüzden sıra kullanıyorum. – user4287276

cevap

8

Sadece iş parçacığı güvenliği eklemek için ConcurrentQueue kullanmalısınız. Bir sıranın iş parçacığı ile güvenli bir şekilde uygulanması ve eşzamanlılık hakkında endişelenmeden bir kuyruğu kullandığınız gibi kullanabilirsiniz.

size kullanmalıdır (meşgul-bekletme veya beklerken bir iş parçacığı engelleme olmadığı anlamına gelir) uyumsuz await yapabilirsiniz kuyruğu istiyorum Ancak eğer sadece, zaten sizin için uygulanan AsyncProducerConsumerCollection çok benzer TPL Veri akışı en BufferBlock MS:

var buffer = new BufferBlock<int>(); 
await buffer.SendAsync(3); // Instead of enqueue. 
int item = await buffer.ReceiveAsync(); // instead of dequeue. 

ConcurrentQueue çekişme yüksek seviyelerde parçacığı güvenliğine yönelik ince ama savurgan olduğunu. BufferBlock sadece iş parçacığı güvenliği sağlamakla kalmaz, aynı zamanda asenkron koordinasyon sağlar (genellikle bir tüketici ve üretici arasında).

+0

Ancak ConcurrentQueue, ConcurrentQueue kullanarak kodun iş parçacığı güvenli olduğunu göstermiyor mu (soruda # 2 bakın)? – user4287276

+0

@ user4287276 'ConcurrentQueue', yöntemlerinden birine yapılan her çağrının kendi başına güvenli olmasını sağlar. Kilitleme mekanizması değil. Kodunuzda senkronizasyona ihtiyacınız varsa, bir 'lock' (veya uygunsa' 'AsyncLock') kullanmalısınız. – i3arnon

İlgili konular