Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Przy pisaniu swojej wersji Wiki-pajączka uwziąłem się, aby znów wrócić do tematu nazwijmy to na razie w cudzysłowiu "optymalizacji pod multi-core". Pod tą optymalizacją oczywiście na razie nie kryję się nic innego jak wielowątkowość.
Uczestnicy zabawy w tym temacie skutecznie upraszczali sobie życie podarunkiem w postaci BackgroundWorker'a. Ja postanowiłem czysto po wątkach zrobić mechanizm, który by jeszcze synchronizował działanie aktualizacji cache'a, statystyk oraz bieżące przeszukiwanie tego co już jest nagromadzone.
W między czasie padł problem synchronizacji wątków i wykorzystywania wspólnych zasobów w sposób bezpieczny w konteście. Tego typu problematykę łatwo spotkać gdy bawimy się Forms'ami i z punktu innego wątku próbujemy zmienić coś w kontrolkach formularza.
Wyskakuje wyjątek i trzeba się niestety pobawić w stworzenie delegatu, sprawdzenie Control.InvokeRequired oraz dalej wykonywać metodę Control.Invoke, która uruchamia funkcje w kontekście wątku gdzie kontrolka została stworzona.
Przykład z mojego jeszcze bałaganiarskiego kodu, który jak posprzątam to w końcu opublikuję:
#region Multithreading safe UI update routinues
//delegates
delegate void updateUI_VoidUpdateCallback();
//routinues
private void updateUI_CacheUpdate()
{
if (labelLoading.InvokeRequired)
{
updateUI_VoidUpdateCallback d = new updateUI_VoidUpdateCallback(updateUI_CacheUpdate);
this.Invoke(d, null);
}
else
{
labelLoading.Text = "Wait.. Web [" + countLoad + "] Cache [" + countUse + "]";
labelLoading.Update();
}
}
#endregion
Zastanawiałem się jak taki mechanizm sobie samemu zrobić. Control nie ma tej funkcjonalności wydzielonej w jakiejś abstrakcyjnej formie, którą można by podpiąć, w sumie i słusznie bo tam zasoby są bardzo konkretnie zdefiniowane, a przynajmniej powinny.
Jedyne o czym Control informuje to fakt, że implementuje interfejs ISynchronizeInvoke zawierający prototypy wszystkich metod związanych z inwokacją :) Super..
Miałem swoje podejrzenia, które zacząłem w swoim bardziej abstrakcyjnym mechanizmie pisać. Podejrzewałem, że Control sprawdza zasobnik z handlerem (tam pewnie HWND) a potem poprzez odpowiednie wiadomości w głównej petli lub system (eventy) przekazuje informacje do odpowiedniego wątku, że ma pobrać pointer do delegatu z funkcją i ją wykonać w swoim kontekście. W swojej wersji też chciałem stworzyć jakiś pojemniczek, który potem można by sobie opakowywać a potem dogrzebać się do SendMessage()/PostMessage() .
Jak wiadomo źródła .NET Framework już sobie podejrzeć można. Co też uczyniłem i sprawdziłem swoje powyższe podejrzenia.
Tak wygląda InvokeRequired w tej klasie Control:
public bool InvokeRequired {
get {
using (new MultithreadSafeCallScope())
{
HandleRef hwnd;
if (IsHandleCreated) {
hwnd = new HandleRef(this, Handle);
}
else {
Control marshalingControl = FindMarshalingControl();
if (!marshalingControl.IsHandleCreated) {
return false;
}
hwnd = new HandleRef(
marshalingControl,
marshalingControl.Handle);
}int pid;
int hwndThread =
SafeNativeMethods.GetWindowThreadProcessId(hwnd, out pid);int currentThread = SafeNativeMethods.GetCurrentThreadId();
return(hwndThread != currentThread);
}}}
Jak nie patrzeć testowane jest HWND i wątek, do którego jest natywnie przypisany.
A teraz jak wygląda Invoke? Powiem tak, krótko :)
public Object Invoke(Delegate method, params Object[] args) {
using (new MultithreadSafeCallScope()) {
Control marshaler = FindMarshalingControl();
return marshaler.MarshaledInvoke(this, method, args, true);
}
}
A bez żartów, przechodząc przez całe ciało ::MarchaledInvoke gdzie sprawdzanych jest mnóstwo warunków, rekonstruowany jest kontekst wykonania w pewnym momencie wykonywany jest kod:
if (syncSameThread) {
InvokeMarshaledCallbacks();
} else {
//
UnsafeNativeMethods.PostMessage(
new HandleRef(this, Handle),
threadCallbackMessage,
IntPtr.Zero,
IntPtr.Zero);
}
Czyli mniej więcej podejrzenia się zgodziły. Analizę asynchronicznego wykonania zostawiam jako pracę domową :)
Technorati Tagi: Polish Posts,coding,.NET Framework,geeks,multicore