Beitragsseiten

1 1 1 1 1 1 1 1 1 1 Rating 0.00 (0 Votes)

Dieses Demo zeigt Beipiele für die Verwendung von Threads:

  • parameterlose Threads
  • parametrisierte Threads
  • Threads in definierten CPU-Cores starten

Screenshot WPF Threads in definierten Cores

Der gesamte Quelltext ist umfassend kommentiert  - und kann von registrierten Benutzern heruntergeladen werden ;)

Für dieses Demo werden folgende Quelltext-Datein verwendet:

  • MainWindow.xaml und MainWindow.xaml.cs
  • App.xaml und App.xaml.cs
  • DemoTools.cs
  • CoredThread.cs

 Besonders wichtige Zeilen sind hervorgehoben.

MainWindow.xaml und MainWindow.xaml.cs

MainWindow.xaml

<Window x:Class="WPFThread.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Thread-Demo" WindowStartupLocation="CenterScreen" SizeToContent="WidthAndHeight" >
    <Grid>
        <StackPanel>
            <TextBlock Text=" parameterloser 'separater' Thread " HorizontalAlignment="Center" FontSize="16" FontWeight="Bold" Background="LightGreen" />
            <ProgressBar Name="bar" Minimum="0" Maximum="100" Width="200" Height="20"  Margin="10"/>
            <Button Name="btnStart" Click="btnStart_Click" Content="Start Progress-Demo" Width="200" Height="30" />
            <TextBlock Text=" parametrisierte 'separate' Threads in definierten Cores " HorizontalAlignment="Center" FontSize="16" FontWeight="Bold" Background="LightGreen" Margin="0,20,0,0" />
            <Grid>
                <Grid.Resources>
                    <Style TargetType="TextBlock">
                        <Setter Property="Width" Value="80" />
                        <Setter Property="Height" Value="30" />
                    </Style>
                    <Style TargetType="Label">
                        <Setter Property="HorizontalAlignment" Value="Center" />
                    </Style>
                    <Style TargetType="Button">
                        <Setter Property="Width" Value="80" />
                        <Setter Property="Height" Value="30" />
                        <Setter Property="Margin" Value="0,5" />
                    </Style>
                </Grid.Resources>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <StackPanel Grid.Column="0">
                    <Label Content="Checking Objects 1 - 10" />
                    <TextBlock Name="tbk1" Tag="1" />
                    <Button Name="btnThings10" Content="Check 1-10" Click="btnCheckObjects_Click" Tag="{Binding ElementName=tbk1}" />
                </StackPanel>
                <StackPanel Grid.Column="1">
                    <Label Content="Checking Objects 11 - 20" HorizontalAlignment="Center" />
                    <TextBlock Name="tbk2" Tag="11" />
                    <Button Name="btnThings20" Content="Check 11-20" Click="btnCheckObjects_Click" Tag="{Binding ElementName=tbk2}" />
                </StackPanel>
                <StackPanel Grid.Column="2">
                    <Label Content="Checking Objects 21 - 30" HorizontalAlignment="Center" />
                    <TextBlock Name="tbk3" Tag="21" />
                    <Button Name="btnThings30" Content="Check 21-30" Click="btnCheckObjects_Click" Tag="{Binding ElementName=tbk3}" />
                </StackPanel>
            </Grid>
        </StackPanel>
    </Grid>
</Window>

 MainWindow.xaml.cs

/*
 * 
 * 
 *          #############
 *          ## ACHTUNG ##
 *          #############
 * 
 *          Dieses Programm ist nur fehlerfrei lauffähig,
 *          wenn eine CPU mit mindestens 8 Cores verwendet wird!
 *          
 *          Ist dies nicht der Fall, müssen die Methoden
 *              btnStart_Click und
 *              btnCheckObjects_Click
 *          entsprechend angepasst werden!
 *          
 * 
 *          #############
 *          ## WICHTIG ##
 *          #############
 *          
 *          Nicht beendete Threads laufen auch nach Beenden der Anwendung weiter!
 *          Um die Threads mit der Anwendung zu beenden, unbedingt die Hinweise
 *          in den DemoTools beachten (siehe Methode Check10Objects)
 *          
 * 
 */

using System.Windows;
using System.Windows.Controls;

using System.Threading;             // erforderlich für die Thread-Delegates (ThreadStart => in btnStart_Click, ParameterizedThreadStart => in btnCheckObjects_Click)
using System;                       // erforderlich für die Dispatcher-Delegate-Methode (Dispatcher.Invoke => in ThreadReady)
using System.Windows.Threading;     // erforderlich, um die Dispatcher-Priorität für Methoden festzulegen, 
                                    // die über separate Threads ausgeführt werden und Elemente des UI-Threads manipulieren sollen (Dispatcher.Invoke => in ThreadReady)

// Eigene Namespaces:
using DemoTools;                    // enthält Methoden, die als separate Threads ausgeführt werden sollen
using UnmanagedCLRThread;           // enthält Funktionalitäten, um separate Threads in festgelegten Cores auszuführen

namespace WPFThread
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // dieser Main-Thread (UI-Thread) muss für die anderen Threads erreichbar sein
        public static MainWindow MainWdw;

        public MainWindow()
        {
            MainWdw = this;
            InitializeComponent();
        }

        /// <summary>
        /// Starte Demo: ProgressBar aus anderem Thread aktualisieren
        /// <para>ACHTUNG: Hinweis-Kommentar am Anfang der MainWindow.xaml.cs-Datei beachten!</para>
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            // Thread-Delegate instanziieren
            ThreadStart progressDemo = Tools.ProgessDemo;

            // parameterlosen Thread starten (Namespace DemoTools, statische Klasse Tools, statische Methode ProgressDemo) 
            new Thread(progressDemo).Start();
            //while (true) { };

            // Alternativ als Demonstration: Thread in Core #8 starten
            //CoredThread thread = new CoredThread(128, progressDemo);
            //thread.Start();
        }

        /// <summary>
        /// Starte Demo: Threads können in fest definierten Cores gestartet werden;
        /// <para>ACHTUNG: Hinweis-Kommentar am Anfang der MainWindow.xaml.cs-Datei beachten!</para>
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCheckObjects_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;          // jeder Button startet einen separaten Thread
            TextBlock tbk = btn.Tag as TextBlock;   // der zum Button zugehörige TextBlock

            btn.IsEnabled = false;

            // Parameter-Objekt für den parametrisierten Thread
            CheckArgs args = new CheckArgs
            {
                TargetTextBlock = tbk,
                FirstObjectOf10 = int.Parse(tbk.Tag.ToString()),
                Ready = ThreadReady,
                ThreadButton = btn
            };
            // Thread-Delegate instanziieren
            ParameterizedThreadStart check = Tools.Check10Objects;

            // parametrisierten Thread starten (Namespace DemoTools, statische Klasse Tools, statische Methode Check10Objects) 
            /* Thread OHNE Festlegung des Core starten (normaler Vorgang)
            Thread t = new Thread(check);
            t.Start(args);
            */

            /* Thread MIT Festlegung des Core starten (benutzt Klasse "CoreThread" zum Kapseln der eigentlichen Threads)
            */
            // über den Start-Index der zu prüfenden Objekte wird hier ein separater CPU-Kern ermittelt und für den Thread festgelegt
            int core = CoredThread.AllCores;  // alle Cores gesetzt -> Core-Auswahl durch OS (default)
            switch (args.FirstObjectOf10)
            {
                case 1: core = 0x02; break;       // Core #2    0000 0010
                case 11: core = 0x08; break;      // Core #4    0000 1000
                case 21: core = 0x20; break;      // Core #6    0010 0000
            }
            CoredThread thread = new CoredThread(core, check);
            thread.Start(args);
        }

        /// <summary>
        /// Methode, die nach Beendigung des Threads vom 'separaten' Thread aufgerufen wird
        /// </summary>
        /// <param name="args"></param>
        private void ThreadReady(CheckArgs args)
        {
            MessageBox.Show(string.Format("Objekte {0} bis {1} wurden geprüft...", args.FirstObjectOf10, --args.FirstObjectOf10 + 10));
            /*
             * der Button kann hier nicht enabled werden, da der Aufruf dieser Methode aus einem anderen Thread erfolgt
             * und demzufolge nicht auf dieses UI-Element zugegriffen werden kann
             */
            //args.ThreadButton.IsEnabled = true;

            /*
             * also muss auch hier wieder die Arbeit über den Dispatcher erledigt werden
             * (zugehörige Methode [enableButton] folgt nach dieser Methode)
             */
            Dispatcher.Invoke(new Action<Button>(enableButton), DispatcherPriority.Background, args.ThreadButton);
        }
        /// <summary>
        /// Methode zum enbablen eines Buttons; 
        /// Aufruf erfolgt durch Thread, der nach Beendigung die o.a. "ThreadReady"-Methode aufruft
        /// </summary>
        /// <param name="btn"></param>
        private void enableButton(Button btn)
        {
            btn.IsEnabled = true;
        }

        /// <summary>
        /// Aktualisierung der ProgressBar
        /// </summary>
        /// <param name="pos"></param>
        public void UpdateProgressBar(int pos)
        {
            bar.Value = pos;
        }

        /// <summary>
        /// Aktualisierung des TextBlock
        /// </summary>
        /// <param name="args"></param>
        public void UpdateTextBlock(CheckArgs args)
        {
            args.TargetTextBlock.Text = args.CurrObject.ToString();
        }
    }



    /// <summary>
    /// Argumente für die parametrisierte Thread-Methode (siehe btnCheckObjects_Click)
    /// </summary>
    public class CheckArgs
    {
        public TextBlock TargetTextBlock { get; set; }   // TextBlock, in dem die Ausgabe erfolgt
        public int FirstObjectOf10 { get; set; }          // "Index" des ersten zu prüfenden Objekts
        public int CurrObject { get; set; }               // "index" des aktuell geprüften Objekts

        // Delegate für eine Methode, die nach Beendigung des Threads aufgerufen werden kann
        public delegate void ThreadReady(CheckArgs args);
        public ThreadReady Ready;
        public Button ThreadButton;     // in dieser Demo wird Button bei ThreadStart disabled und nach Beendigung des Threads wieder enabled
    }

}

Hätten Sie's gewusst?

Angemeldete User können Kommentare verfolgen und bei Antworten auf Kommentare per Email benachrichtigt werden.

Wussten Sie's schon?

Für Kommentare und Fehlerhinweise bin ich Ihnen immer dankbar. Benutzen Sie hierfür bitte das Kontaktformular oder die Kommentar-Funktion des jeweiligen Beitrags - eine Anmeldung ist hierfür nicht erforderlich. Wollen Sie jedoch über Reaktionen zu Kommentaren per Email informiert werden, dann melden Sie sich bitte an.