În WinForms, de ce nu puteți actualiza controalele UI din alte fire?

Sunt sigur că există un motiv bun (sau cel puțin decent) pentru acest lucru. Ce este?

0
fr hi bn

8 răspunsuri

Este așa încât să nu aveți două lucruri care încearcă să actualizeze controlul în același timp. (Acest lucru se poate întâmpla dacă CPU trece la celălalt fir din mijlocul unei scriere/citire) Același motiv este necesar să utilizați mutexuri (sau o altă sincronizare) atunci când accesați variabilele partajate între mai multe fire.

Editați | ×:

În alte limbi, cum ar fi C ++, sunteți   libertatea de a încerca și de a face acest lucru (fără un   excepție fiind aruncat ca în   WinForms), dar veți termina învățarea   calea grea!

Ahh da ... Schimba între C/C și C# și, prin urmare, a fost un pic mai generic, atunci ar fi trebuit, îmi pare rău ... El este corect, puteți face acest lucru în C/C + , dar se va întoarce să te muște!

0
adăugat

Cred că este o întrebare strălucită - și cred că este nevoie de un răspuns mai bun.

Cu siguranță, singurul motiv este că există ceva într-un cadru undeva, care nu este foarte sigur pentru fire. Este o problemă cu .NET sau Win32 - și de ce nu există o împingere pentru a remedia sursa în loc de a impune ceea ce, pentru mine, se simte ca un lucru urât?

Oricine știe unde este problema reală?

0
adăugat

Pentru că puteți ajunge ușor la un impas (printre altele).

De exemplu, firul dvs. secundar ar putea încerca să actualizeze controlul UI, dar controlul UI va aștepta o resursă blocată de firul secundar care urmează să fie eliberat, astfel încât ambele fire ajung să aștepte unul pe celălalt să termine. După cum au comentat alții, această situație nu este unică pentru codul UI, ci este deosebit de comună.

În alte limbi, cum ar fi C ++, sunteți liberi să încercați să faceți acest lucru (fără a fi aruncată o excepție ca în WinForms), dar aplicația dvs. poate îngheța și nu mai răspunde dacă apare un blocaj.

De altfel, puteți spune cu ușurință că firul UI doriți să actualizați un control, trebuie doar să creați un delegat, apoi să apelați metoda (asincronă) BeginInvoke pe acel control prin care îl transmiteți delegatului. De exemplu.

myControl.BeginInvoke(myControl.UpdateFunction);

Aceasta este echivalentă cu a face un C ++/MFC PostMessage dintr-un thread lucrător

0
adăugat
-1: așteptarea pentru resursele blocate nu este problema. Problema este condițiile de rasă care există în cantități mari în orice cod care nu a fost conceput pentru a fi utilizat în medii cu mai multe filete. Puteți chiar verifica acest lucru prin setarea CheckForIllegalCrossThreadCaută la fals și observați funcționarea fără blocaj, până se întâmplă ceva amuzant.
adăugat autor Roman Starkov, sursa
Nu sunt sigur de ce a fost acceptat acest răspuns. Acest lucru nu este pur și simplu răspunsul corect. Momentele de blocare pot apărea ori de câte ori aveți mai multe fire. Nu este nimic inerent în programele GUI care le face mai multe șanse să se întâmple. Mai mult, ele se pot întâmpla cu ușurință chiar dacă folosiți BeginInvoke (). Răspunsul lui Brian Ensink este unul corect.
adăugat autor mhenry1384, sursa

Înapoi în 1.0/1.1 nu a fost aruncat nici o excepție în timpul depanării, ceea ce ați avut în schimb a fost un scenariu intermitent de executare. Frumos! :) Prin urmare, cu 2.0 au făcut acest scenariu să arunce o excepție și pe bună dreptate.

Motivul real pentru acest lucru este, probabil, (după cum spune Adam Haile) un fel de problemă de concurrency/locky. Rețineți că apiterele .NET normale (cum ar fi TextBox.Text = "Hello";) împachetează comenzile SEND (care necesită acțiuni imediate) care pot crea probleme dacă sunt efectuate pe fir separat de cel care acționează actualizarea. Folosind Invoke/BeginInvoke utilizează în schimb un POST care cedează acțiunea.

Mai multe informații despre SEND și POST aici .

0
adăugat

De asemenea, ar fi nevoie să se implementeze sincronizarea în cadrul funcțiilor de actualizare care sunt sensibile la apelarea simultană. Făcând acest lucru pentru elementele UI ar fi costisitoare atât la nivel de aplicație, cât și la nivel de sistem de operare și complet redundante pentru majoritatea codurilor.

Unele interfețe API oferă o modalitate de a schimba proprietatea curentă a unui sistem, astfel încât să puteți actualiza temporar (sau permanent) sistemele din alte fire, fără a fi nevoie să recurgeți la o comunicare între fire.

0
adăugat

Cred că aceasta este o întrebare strălucită -   și cred că este nevoie de o mai bună   răspuns.

     

Cu siguranță că singurul motiv este că există   este ceva într-un cadru undeva   care nu este foarte sigur de fir.

Acest "ceva" este aproape fiecare membru de instanță la fiecare control din System.Windows.Forms.

The MSDN documentation for many controls in System.Windows.Forms, if not all of them, say "Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe."

Aceasta înseamnă că membrii instanțelor, cum ar fi TextBox.Text {get; set;} nu sunt reentrant .

Efectuarea fiecărui membru al acelei instanțe în siguranță ar putea introduce o mulțime de cheltuieli generale pe care majoritatea aplicațiilor nu le au nevoie. În schimb, designerii framework-ului .Net au decis, și cred că în mod corect, că povara sincronizării accesului la controalele de formulare din fire multiple ar trebui pusă pe programator.

[Editați | ×]

Deși această întrebare doar întreabă "de ce" aici este o legătură către un articol care explică "cum":

How to: Make Thread-Safe Calls to Windows Forms Controls on MSDN

http://msdn.microsoft.com/en-us/library/ms171728.aspx

0
adăugat
Este cu totul posibil să fii reentrant, dar nu sigur de fir. Luați în considerare (f) => {x + = 1; f (x); x - = 1; }, care este fin până la depășire dacă f (x) reintră lambda pe un fir, dar curse pe x dacă multithreaded.
adăugat autor Jeffrey Hantin, sursa

Nu sunt destul de sigur, dar cred că atunci când avem controale de progres cum ar fi bare de așteptare, bare de progres ne putem actualiza valorile dintr-un alt fir și totul funcționează excelent fără nici un fel de glitches.

0
adăugat

Deși suna rezonabil, răspunsul lui Johns nu este corect. De fapt, chiar și atunci când utilizați Invoke, nu sunteți în siguranță în situații în care nu vă aflați în situații de blocare. Atunci când se ocupă de evenimente trase pe un fir de fundal folosind Invoke ar putea duce chiar la această problemă.


Motivul real are mai mult de-a face cu condițiile de rasă și se află în vremurile antice Win32. Nu pot explica detaliile aici, cuvintele cheie sunt pompele de mesaje, evenimentele WM_PAINT și diferențele subtile dintre "TRIMITE" și "POST".


Mai multe informații pot fi găsite aici aici și aici .

0
adăugat