SORU
1 EYLÜL 2009, Salı


/Çapraz iş parçacığı Beginınvoke Çağırma sıkıntılardan kaçınmak WinForm olay işleme?

Hala WinForm UI arka plan iş parçacığı tarafından rahatsız oluyorum. Neden? İşte sorunlardan bazıları:

  1. Açıkçası en önemli sorunu, onu yaratan aynı konu üzerinde yürütülen olmadığım sürece bir Kontrol getirebilirim.
  2. Bildiğiniz gibi, Çağırmak, Beginınvoke, vb bir Kontrol oluşturulduktan sonra kadar kullanılamaz.
  3. Requiresİnvoke true değerini döndürür sonra bile, Beginınvoke hala ObjectDisposed atabilir ve eğer atmak değil ise bile, hiç değilse kontrol edilir Eğer kodu yürütür.
  4. Requiresİnvoke true değerini döndürür sonra bile, sonsuza kadar Çağırmak Çağırmak için çağrı aynı zamanda elden bir denetim tarafından yürütülmesi için bekleyecek.

Bu sorun için zarif bir çözüm arıyorum, ama aradığım şey bu ayrıntıya girmeden önce, bu sorunu açıklığa kavuşturmak istedim. Bu genel bir sorun arkasına daha somut bir örnek koymaktır. Bu mesela internet üzerinden büyük miktarlarda veri aktarımı olduğunu söylüyor. Kullanıcı arayüzü bir ilerleme devri için halihazırda devam etmekte olan iletişim göstermek gerekir. İlerleme sürekli iletişim ve hızlı bir şekilde (saniyede güncellemeleri 5 ila 20 defa) güncellemelidir. Kullanıcı ilerleme iletişim herhangi bir zamanda kapatmak ve istenirse tekrar çağırabilirsiniz. Ve daha fazla olanak sağlar, bağımsız gibi iletişim görünmüyorsa, her ilerleme olayın yaşanması gereken iyiliği. Kullanıcı ilerleme iletişim kutusunda İptal ' i tıklatın ve olay değişkenlerini değiştirme yoluyla, işlemi iptal edebilirsiniz.

Şimdi kısıtlamaları aşağıdaki kutuya uyacak bir çözüm istiyorum:

  1. Bir iş parçacığı Denetimi bir Form üzerinde bir yöntemi çağırmak için izin ve/yürütme tamamlanana kadar bekleyin blok.
  2. Kendisi başlatma veya benzeri (ve böylece çağırmak kullanın) Bu aynı yöntemi çağırmak için iletişim sağlar.
  3. İşleme yöntemi veya çağıran olay üzerinde uygulama hiçbir yük, çözüm sadece olayı abonelik değiştirmek gerekir.
  4. Uygun engelleme kolu atılması işleminde olabilecek bir iletişim için çağırır. Ne yazık ki bu İsDisposed kontrol kadar kolay değildir.
  5. Herhangi bir olay türü (tip EventHandler temsilci kabul) ile kullanılması gerekir
  6. Targetınvocationexception istisnaları değil çevirmek gerekir.
  7. Çözüm ile çalışmak gerekir .Net 2.0 ve daha yüksek

Bu kısıtlamalar, yukarıda verilen çözülebilir? Ve sayısız bloglar ve tartışma aranan kazdım ve ne yazık ki hala elim boş geldim.

Güncelleme: bu sorunun kolay bir cevabı yoktur, bunu fark ediyorum. Sadece birkaç gün için bu sitede ettik ve bazı insanlar deneyim bir sürü soru cevap gördüm. Bu kişilerin beni bir hafta geçirmek için yeterli bu yeterince çözmüş ya da makul bir çözüm oluşturmak için daha uzun sürer diye umuyorum.

Güncelleme #2: Tamam, biraz daha ayrıntılı olarak sorunu tarif deneyin ve bakalım ne çıkacak edeceğim. Biz durumunu belirlemek için izin aşağıdaki özelliklere endişelerini dile birkaç şey var

  1. Kontrol.= Eğer geçerli iş parçacığı üzerinde çalışan eğer yanlış veya İsHandleCreated verir tüm anne-babalar için sahte dönüş için Belgelenmiş ınvokerequired. InvokeRequired uygulanması da ObjectDisposedException atmak potansiyeline sahip rahatsız oldum veya yeniden oluşturmak potansiyel olarak bile nesneyi işlemek. Ve o zamandan beri InvokeRequired dönebilirsiniz doğru zaman değildir mümkün çağırmak için (Atma ilerleme) ve return false olsa bile ihtiyacımız olabilir kullanın çağırmak (Oluşturma ilerleme) bu sadece güvenilmiyor her zaman. Güvenebileceğimiz tek durumda yanlış dönen InvokeRequired İsHandleCreated true değerini döndürür ve çağrı öncesi ve sonrası (MSDN InvokeRequired için dokümanlar BTW İsHandleCreated kontrol söz yok).

  2. Kontrol.İsHandleCreated = kontrol kolu atandı; aksi takdirde, yanlış ise doğru değerini Verir. Eğer kumanda kolu bu yeniden yaratma süreci içinde olsa İsHandleCreated. arıza olabilir güvenli bir telefon. Bu potansiyel sorun İsHandleCreated erişme ve InvokeRequired kilit(kontrol) uygulayarak solveable görünüyor.

  3. Kontrol.= Atılmasının eğer kontrol yardımcı olduğu süreçte ise true değerini gönderir.

  4. Kontrol.İsDisposed = eğer denetim bertaraf edildiği takdirde, true değerini Döndürür. Bertaraf olay abone ve İsDisposed özelliği ise Beginınvoke hiç tamamlayacak eğer ölçüm m kontrol düşünüyorum. Buradaki en büyük sorun senkronizasyon kilit Atılması - ^ sırasında eksikliğidir . Geçiş bertaraf. O == false & & = = İsDisposed Atılmasının yanlış doğruladıktan sonra eğer Bertaraf olay abone olursanız ve hala asla Bertaraf olay yangını olabilir. Bu = true İmha uygulanmasına yardımcı olduğu = yanlış ayarlar, ve daha sonra İmha ayarlayan kaynaklanmaktadır. Bu oppertunity bir sağlar (ancak küçük) elden denetimi konusunda hem de yanlış olarak İsDisposed Elden okumak.

... başım ağrıyor :( Umarım Yukarıdaki bilgiler herkes bu sorunları için bu konular üzerinde biraz daha fazla ışık tutacaktır. Boş düşünce bu devir için minnettarım.

Sorun üzerinde kapanış... ... aşağıdaki Kontrol sonraki yarısıdır.() DestroyHandle yöntemi:

if (!this.RecreatingHandle && (this.threadCallbackList != null))
{
    lock (this.threadCallbackList)
    {
        Exception exception = new ObjectDisposedException(base.GetType().Name);
        while (this.threadCallbackList.Count > 0)
        {
            ThreadMethodEntry entry = (ThreadMethodEntry) this.threadCallbackList.Dequeue();
            entry.exception = exception;
            entry.Complete();
        }
    }
}
if ((0x40 & ((int) ((long) UnsafeNativeMethods.GetWindowLong(new HandleRef(this.window, this.InternalHandle), -20)))) != 0)
{
    UnsafeNativeMethods.DefMDIChildProc(this.InternalHandle, 0x10, IntPtr.Zero, IntPtr.Zero);
}
else
{
    this.window.DestroyHandle();
}

Bu ObjectDisposedException çapraz iş parçacığı tüm bekleyen çağırmaları için dağıtılan fark edeceksiniz. Kısa bir süre sonra bu aşağıdaki bu çağrı.pencere.() DestroyHandle da pencere yok ve IntPtr başvuru kolu bu set.Sıfır böylece daha fazla önleme Beginınvoke yöntemi (hem Beginınvoke kolu olan ya da daha doğrusu) ve Çağırmak Marshaledİnvoke çağırır. Sorun burada kilit yeni bir giriş Denetim iş parçacığı sıfır önce eklenebilir threadCallbackList bültenleri sonra pencere kolu. Bu gördüğüm durum, seyrek olarak, bir serbest durdurmak için genellikle yeterli olsa görünüyor.

Güncelleme #4:

Üzgünüm bu sürüncemede tutmak; ancak, burada belgeleyen değer diye düşündüm. Sorunların en yukarıdaki çözmeyi başardım ve çalışan bir çözüm üzerinde daralma ediyorum. Endişe ettim bir daha sorun vurmadım ama şu ana kadar görmedim 'in-the-vahşi'.

Bu sorunu Kontrol yazan bir dahi ile bir ilgisi yoktur.Mülk idare:

	public IntPtr get_Handle()
	{
		if ((checkForIllegalCrossThreadCalls && !inCrossThreadSafeCall) && this.InvokeRequired)
		{
			throw new InvalidOperationException(SR.GetString("IllegalCrossThreadCall", new object[] { this.Name }));
		}
		if (!this.IsHandleCreated)
		{
			this.CreateHandle();
		}
		return this.HandleInternal;
	}

Kendisi tarafından o kadar da kötü değildir (düşüncelerimi bağlı olmaksızın, { } değişiklikler); InvokeRequired özelliği ile kombine edildiğinde, ancak, ya da/Çağırmak Beginınvoke yöntemi kötü. Burada Çağırmak temel akış:

if( !this.IsHandleCreated )
    throw;
... do more stuff
PostMessage( this.Handle, ... );

Burada sorun olan başka bir konu olabilir başarıyla geçerek ilk if ifadesi, ve daha sonra idare tarafından tahrip edilir denetim iş parçacığı, böylece yol almak Sapı özelliği yeniden oluşturmak pencere kolu benim iplik. Bu özgün denetim iş parçacığı üzerinde yükseltilmiş olması için bir özel durum neden olabilir. Bu gerçekten bu karşı korumak için bir yol yok gibi beni de şaşırttı. Onlar İnternalHandle özelliğini kullanın ve IntPtr sonucu test vardı sadece.Bu bir sorun olmazdı sıfır.

CEVAP
1 EYLÜL 2009, Salı


Açıklanan senaryo, düzenli bir şekilde BackgroundWorker - neden bunu kullanmıyorsun? uyuyor Çözüm için gereksinimleri çok genel ve oldukça mantıksız bir şekilde - hepsini tatmin edecek bir çözüm olduğunu sanmıyorum.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BlackmillMusic

    BlackmillMus

    3 Kasım 2010
  • ColdfusTion

    ColdfusTion

    3 Aralık 2007
  • PlayStation

    PlayStation

    16 Aralık 2005