Windows futtatókörnyezeti objektumok használata többszálú környezetben

Ez a cikk azt ismerteti, hogyan kezeli a .NET-keretrendszer a C# és a Visual Basic kódból érkező hívásokat a Windows Futtatókörnyezet vagy a Windows Futtatókörnyezet összetevői által biztosított objektumokhoz.

A .NET-keretrendszerben alapértelmezés szerint több szálból is elérheti az objektumokat speciális kezelés nélkül. Mindössze az objektumra mutató hivatkozásra van szüksége. A Windows futtatókörnyezetben az ilyen objektumokat agilisnak nevezzük. A Windows futtatókörnyezeti osztályok többsége agilis, de néhány osztály nem, és még az agilis osztályok is speciális kezelést igényelhetnek.

Ahol csak lehetséges, a közös nyelvi futtatókörnyezet (CLR) úgy kezeli a más forrásokból származó objektumokat, mint például a Windows futtatókörnyezetet, mintha .NET-keretrendszer-objektumok lennének:

  • Ha az objektum implementálja az IAgileObject interfészt, vagy a MarshalingBehaviorAttribute attribútummal rendelkezik a MarshalingType.Agile használatával, a CLR agilisként kezeli.

  • Ha a CLR képes egy hívás átirányítására arról a szálról, amelyen az eredetileg történt, a célobjektum szálkezelési környezetébe, akkor ezt átlátható módon végzi.

  • Ha az objektum MarshalingBehaviorAttribute attribútummal rendelkezik a MarshalingType.None tulajdonsággal, az osztály nem ad meg marsallálási információkat. A CLR nem tudja kezdeményezni a hívást, ezért érvénytelenCastException kivételt jelez, amely azt jelzi, hogy az objektum csak abban a szálkezelési környezetben használható, ahol létrejött.

A következő szakaszok a viselkedés különböző forrásokból származó objektumokra gyakorolt hatását ismertetik.

C# vagy Visual Basic nyelven írt Windows Runtime-összetevő objektumai

Az összetevő összes aktiválható típusa alapértelmezés szerint agilis.

Megjegyzés:

Az agilitás nem jelenti a szál biztonságát. A Windows futtatókörnyezetben és a .NET-keretrendszerben a legtöbb osztály nem biztonságos a szálbiztonsággal, mert a szálbiztonság teljesítményköltséggel jár, és a legtöbb objektumhoz soha nem fér hozzá több szál. Hatékonyabb az egyes objektumokhoz való hozzáférés szinkronizálása (vagy a szálbiztos osztályok használata) csak szükség esetén.

Windows futtatókörnyezeti összetevő létrehozásakor felülbírálhatja az alapértelmezett értéket. Lásd az ICustomQueryInterface felületet és az IAgileObject felületet.

Objektumok a Windows futtatókörnyezetből

A Windows Futtatókörnyezet legtöbb osztálya agilis, a CLR pedig agilisként kezeli őket. Az osztályok dokumentációja a "MarshalingBehaviorAttribute(Agile)" értéket sorolja fel az osztályattribútumok között. Néhány ilyen agilis osztály, például az XAML-vezérlők tagjai azonban kivételeket vetnek ki, ha nem hívják meg őket a felhasználói felületi szálon. Az alábbi kód például egy háttérszál használatával próbálja beállítani a kattintott gomb tulajdonságát. A gomb Content tulajdonsága kivételt eredményez.

private async void Button_Click_2(object sender, RoutedEventArgs e)
{
    Button b = (Button) sender;
    await Task.Run(() => {
        b.Content += ".";
    });
}
Private Async Sub Button_Click_2(sender As Object, e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    Await Task.Run(Sub()
                       b.Content &= "."
                   End Sub)
End Sub

A gombot biztonságosan érheti el a Dispatcher tulajdonságával, vagy a Dispatcher felhasználói felületi szál környezetében található objektumok tulajdonságával (például azon az oldalon, amelyen a gomb található). Az alábbi kód a CoreDispatcher objektum RunAsync metódusával küldi el a hívást a felhasználói felületen.

private async void Button_Click_2(object sender, RoutedEventArgs e)
{
    Button b = (Button) sender;
    await b.Dispatcher.RunAsync(
        Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => {
            b.Content += ".";
    });
}

Private Async Sub Button_Click_2(sender As Object, e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    Await b.Dispatcher.RunAsync(
        Windows.UI.Core.CoreDispatcherPriority.Normal,
        Sub()
            b.Content &= "."
        End Sub)
End Sub

Megjegyzés:

A Dispatcher tulajdonság nem okoz kivételt, ha egy másik szálról hívják.

A felhasználói felületen létrehozott Windows Futtatókörnyezet objektum élettartamát a szál élettartama határozza meg. Az ablak bezárása után ne próbáljon meg hozzáférni egy felhasználói felületi szál objektumaihoz.

Ha saját vezérlőt hoz létre egy XAML-vezérlő öröklésével vagy XAML-vezérlők megírásával, akkor a vezérlő agilis, mert .NET-keretrendszer-objektum. Ha azonban meghívja az alaposztály vagy az azt alkotó osztályok tagjait, vagy ha öröklött tagokat hív meg, ezek a tagok kivételeket fognak kivenni, ha a felhasználói felületi szál kivételével bármely szálról meghívják őket.

Olyan osztályok, amelyek nem hajthatóak be

Azok a Windows futtatókörnyezeti osztályok, amelyek nem adnak meg marshaling információt, az MarshalingBehaviorAttribute attribútummal rendelkeznek MarshalingType.None. Az ilyen osztály dokumentációja a "MarshalingBehaviorAttribute(None)" értéket sorolja fel attribútumai között.

Az alábbi kód létrehoz egy CameraCaptureUI objektumot a felhasználói felület szálán, majd megpróbálja beállítani az objektum tulajdonságát egy szálkészlet száláról. A CLR nem tudja végrehajtani a hívást, és System.InvalidCastException kivételt küld egy üzenettel, amely azt jelzi, hogy az objektum csak abban a szálkezelési környezetben használható, ahol létrejött.

Windows.Media.Capture.CameraCaptureUI ccui;

private async void Button_Click_1(object sender, RoutedEventArgs e)
{
    ccui = new Windows.Media.Capture.CameraCaptureUI();

    await Task.Run(() => {
        ccui.PhotoSettings.AllowCropping = true;
    });
}

Private ccui As Windows.Media.Capture.CameraCaptureUI

Private Async Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
    ccui = New Windows.Media.Capture.CameraCaptureUI()

    Await Task.Run(Sub()
                       ccui.PhotoSettings.AllowCropping = True
                   End Sub)
End Sub

A CameraCaptureUI dokumentációja a "ThreadingAttribute(STA)" értéket is felsorolja az osztály attribútumai között, mivel egyszálas környezetben kell létrehozni, például a felhasználói felületi szálon.

Ha egy másik szálról szeretné elérni a CameraCaptureUI objektumot, gyorsítótárba helyezheti a CoreDispatcher objektumot a felhasználói felület szálához, és később felhasználhatja a hívás elküldéséhez. Vagy beszerezheti a diszpécsert egy XAML-objektumból, például a lapról, ahogy az az alábbi kódban is látható.

Windows.Media.Capture.CameraCaptureUI ccui;

private async void Button_Click_3(object sender, RoutedEventArgs e)
{
    ccui = new Windows.Media.Capture.CameraCaptureUI();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => {
            ccui.PhotoSettings.AllowCropping = true;
        });
}

Dim ccui As Windows.Media.Capture.CameraCaptureUI

Private Async Sub Button_Click_3(sender As Object, e As RoutedEventArgs)

    ccui = New Windows.Media.Capture.CameraCaptureUI()

    Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                                Sub()
                                    ccui.PhotoSettings.AllowCropping = True
                                End Sub)
End Sub

A C++ nyelven írt Windows Futtatókörnyezet összetevő objektumai

Alapértelmezés szerint az aktiválható összetevő osztályai agilisak. A C++ azonban jelentős mértékű vezérlést tesz lehetővé a szálmodellek és az őrlési viselkedés felett. A cikk korábbi részében leírtak szerint a CLR felismeri az agilis osztályokat, megkísérli az együttműködés megszervezését, amikor az osztályok nem agilisak, és dob egy System.InvalidCastException kivételt, ha egy osztály nem rendelkezik marshaling információval.

A felhasználói felületi szálon futó objektumok, amelyek hibát okoznak, ha nem a felhasználói felületi szálhoz tartozó szálról hívják meg őket, a hívást elirányíthatja a felhasználói felületi szál CoreDispatcher objektumának használatával.

Lásd még:

C# útmutató

Visual Basic Útmutató