Laden...

Threads und Priorität

Erstellt von steffen_dec vor 17 Jahren Letzter Beitrag vor 17 Jahren 2.110 Views
S
steffen_dec Themenstarter:in
322 Beiträge seit 2007
vor 17 Jahren
Threads und Priorität

Hallo Leute,

mein Beispiel klappt irgendwie nicht ganz nach der Theorie der Priorität... oder ich hab ein Denkfehler 🙁


        Thread t1;
        Thread t2;
        Thread t3;
        
        private void cmdTestThreading_Click(object sender, EventArgs e)
        {
            
            t1 = new Thread(new ThreadStart(fred1));
            t2 = new Thread(new ThreadStart(fred2));
            t3 = new Thread(new ThreadStart(fred3));
            listBox1.Items.Clear();
            t1.Priority = ThreadPriority.Highest;
            t2.Priority = ThreadPriority.BelowNormal;
            t3.Priority = ThreadPriority.Lowest;
            
            t1.Start();
            t2.Start();
            t3.Start();           
        }

        void fred1()
        {
            for (int i = 0; i <= 100; i++)
            {
                    AddText("1111" + " => " + i.ToString());
            }
        }

        void fred2()
        {
            for (int i = 0; i <= 100; i++)
            {
                    AddText("2222" + " => " + i.ToString());
            }
        }

        void fred3()
        {
            for (int i = 0; i <= 100; i++)
            {
                    AddText("3333" + " => " + i.ToString());
            }
        }

        private void AddText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.listBox1.InvokeRequired)
            {
                AddTextCallback d = new AddTextCallback(AddText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.listBox1.Items.Add(text);
            }
        }

wenn ich die Priorität auf standard lasse dann erhalte ich immer:

1111 => 0
2222 => 0
3333 => 0
1111 => 1
2222 => 1
3333 => 1
1111 => 2
2222 => 2
3333 => 2
... usw

wenn ich die Prioritäten wie oben im Code setze dann kriege ich diese Reihenfolge:

1111 => 0
1111 => 1
1111 => 2
2222 => 0
3333 => 0
1111 => 3
2222 => 1
3333 => 1
1111 => 4
2222 => 2
3333 => 2
1111 => 5
...usw

wobei sich die Reihenfolgen bei jedem aufruf auch bisschen ändert...

müsste theoretisch nicht diese Reihenfolge rauskommen?

1111 => 0
1111 => 1
1111 => 2
...
1111 => 99
1111 => 100
2222 => 0
2222 => 1
2222 => 2
...
2222 => 99
2222 => 100
3333 => 0
3333 => 1
3333 => 2
....
3333 => 99
3333 => 100

Ich möchte praktisch dass Thread1 die höchste Priorität hat, und ich ihn jederzeit starten kann (ohne warten zu müssen) die anderen Threads müssen dann solange warten bis Thread1 fertig ist

Man kann ja jetzt einfach die anderen Task auf suspend stellen, aber dass ist ja auch nicht das ware, weil ich dann später z.b. 11 oder noch mehr Threads habe...

Vielen Dank für Eure Anregungen.

MFG
Steffen

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo steffen_dec,

Control.Invoke provoziert einen Thread-Wechsel. Das bringt so ziemlich alles durcheinander. Verwende mal Control.BeginInvoke.

herbivore

S
steffen_dec Themenstarter:in
322 Beiträge seit 2007
vor 17 Jahren

Hallo herbivore,

danke für deinen Beitrag!

stimmt es so?


private void AddText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.listBox1.InvokeRequired)
            {
                AddTextCallback d = new AddTextCallback(AddText);
                this.BeginInvoke(d, new object[] { text });
                //this.Invoke(d, new object[] { text });
            }
            else
            {
                this.listBox1.Items.Add(text);
            }
        }

so sieht es schon besser aus, aber dennoch springt manchmal Thread2 rein

ich bin noch Anfänger in C# und .Net 🤔

Gruß
Steffen

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo steffen_dec,

eine höhere Priorität verhindert nicht, dass Prozesse/Threads mit geringerer Priorität auch ab und zu mal drankommen. Sonst würde ein Prozess mit hoher Priorität das ganze System lahmlegen. Ist also alles ok.

herbivore

S
steffen_dec Themenstarter:in
322 Beiträge seit 2007
vor 17 Jahren

Hallo herbivore,

heißt es dass ich nicht drum rum komme, die anderen Threads (zumindest die von meinem Programm) in suspend-Modus setze und am Ende wieder resume!?

So wäre ich auf der sicheren Seite oder?

Danke nochmal für deine Aufklärung 🙂

Gruß
Steffen

6.862 Beiträge seit 2003
vor 17 Jahren

Wozu überhaupt Threads wenn die Aktionen hintereinander ausgeführt werden sollen? Wenns darum geht das z.B. die GUI nicht blockieren soll, dann ists doch einfacher nur einen Thread zu starten und dort halt die Aktionen hintereinander auszuführen.

Baka wa shinanakya naoranai.

Mein XING Profil.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo steffen_dec,

wenn du willst, dass Threads bestimmte Aktionen nicht gleichzeitig machen, musst du sie synchronisieren. Das ist ein Thema für sich und da kommt man nicht drum rum sich gründlich einzuarbeiten. Suspend und Resume wären ein schlechtes Mittel, zumal diese Methoden depricated sind. Normalerweise wird mal lock verwenden. Man kann aber auch AutoResetEvent o.ä. verwenden, je nach den konkreten Anforderungen.

Wenn du aber nur willst, dass deine Aufgaben nacheinander abgearbeitet werden, dann pack sie doch einfach in einen Thread. 🙂

herbivore

S
steffen_dec Themenstarter:in
322 Beiträge seit 2007
vor 17 Jahren

Hallo,

Lock dient doch dazu, damit die Threads einen Code-Abschnitt nicht gleichzeitig ausführen oder?

Ich kann es nicht in einen Thread packen, da das ganze über einen(bzw. mehrere) Event (Interrupt von einer I/O-Karte) gesteuert wird, und bei einem bestimmten Event muss ich was höher prioritäres (sagt man es so 🤔 ) erledigen.

Gruß
Steffen

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo steffen_dec,

Windows ist eh kein Echtzeit-Betriebssystem. Wenn du was höher priorisiertes tun willst, dann setzte die Priorität hoch. Vermeiden, dass Windows statt deiner wichtigen Aufgaben lieber was anderes tut, kannst du eh nicht.

herbivore

S
steffen_dec Themenstarter:in
322 Beiträge seit 2007
vor 17 Jahren

Hallo,

ja dass ist mir schon klar, ich dachte dass ich damit wenigstens meine eigenen Threads in Griff hätte in dem ich die Priorität anders vergebe...

mal sehen wie sich das auswirkt wenn ich schon soweit bin...

Gruß
Steffen

6.862 Beiträge seit 2003
vor 17 Jahren

Dann bleibt dir wohl nur Threadsynchronisation um wenigstens in deinen Threads ne Priorisierung hinzubekommen.

Baka wa shinanakya naoranai.

Mein XING Profil.

B
1.529 Beiträge seit 2006
vor 17 Jahren

Zur Klärung:
Windows verteilt Prozessorzeit mittels preemptiven Multitaskings. Das bedeutet, jeder Thread bekommt einen Zeitrahmen (Standard: 50ms), ist dieser beendet, wird der Thread angehalten und der nächste wiederaufgenommen.
Ein Thread kann drei schedulerrelevante Status haben: Running, Ready To Run oder Waiting.
Es gibt pro Prozessor nur einen Thread mit dem Status "Running". Dies ist der gerade ausgeführte. Wenn der nächste zum Zuge kommen soll, sucht der Scheduler nach Threads mit dem Status "Ready To Run" und führt denjenigen mit der höchsten Priorität aus (Status wird zu "Running"). Ist der Zeitrahmen vorbei (bzw. wird beendet), wird dieser Thread auf den Status "Ready To Run" gestellt und ein Flag gesetzt, dass er in diesem Durchlauf bereits lief.
Gibt es mehrere Threads mit gleicher Priorität wird derjenige ausgeführt, der noch kein gesetztes Flag hat. Gibt es einen solchen nicht, wird das Flag bei allen wieder entfernt.
Der Status "Waiting" wird durch bestimmte Systemfunktionen vergeben, die größtenteils ein Wait im Namen tragen. Oder auch durch Control.Invoke. Er besagt, dass der Thread zwar noch läuft, momentan jedoch nicht ausgeführt werden braucht, da er auf den Abschluß einer Aktion wartet.

Damit ist klar, warum so eine scheinbar merkwürdige Reihenfolge herauskommt.
Alle Threads beenden ihren Zeitrahmen beim Aufruf von Control.Invoke. Da sie die gleiche Priorität haben, werden sie reihum ausgeführt.
Haben sie jetzt unterschiedliche Prioritäten, so kommen die niedriger priorisierten nur dann zum Zuge, wenn alle höheren nichts zu tun haben.
Allerdings kann das Laufzeitverhalten jetzt nicht mehr vorhergesagt werden, da ja nicht genau bekannt ist, wann die per Control.Invoke in einem anderen Thread gestartetet Methode beendet ist und der Thread wieder zu "Ready To Run" zurückkehrt. In genau diesen Zeiten kommt ein niedriger priorisierter Thread zum Zug, auch er bleibt beim Control.Invoke hängen und macht "Platz" für den nächsten.

Da es jetzt aber noch ganz viele andere Threads anderer Prozesse auf dem System gibt, ist das wirkliche Verhalten noch viel komplexer.

S
8.746 Beiträge seit 2005
vor 17 Jahren

Deswegen Finger weg von den Thread-Prioritäten.

S
steffen_dec Themenstarter:in
322 Beiträge seit 2007
vor 17 Jahren

Hallo,

die Prioritäten sind doch da um diese zu nutzen, warum also nicht??

Danke Borg, so gehts nun einwandfrei


Thread t1;
        Thread t2;
        Thread t3;
        private ArrayList liste = new ArrayList();

        private void cmdTestThreading_Click(object sender, EventArgs e)
        {
            
            t1 = new Thread(new ThreadStart(fred1));
            t2 = new Thread(new ThreadStart(fred2));
            t3 = new Thread(new ThreadStart(fred3));
            listBox1.Items.Clear();
            t1.Priority = ThreadPriority.Highest;
            t2.Priority = ThreadPriority.BelowNormal;
            t3.Priority = ThreadPriority.Lowest;
            
            t1.Start();
            t2.Start();
            t3.Start();
            t1.Join();
            t2.Join();
            t3.Join();

            listBox1.Items.AddRange(liste.ToArray());
        }

        void fred1()
        {
            for (int i = 0; i <= 100; i++)
            {
                liste.Add("1111" + " => " + i.ToString());
            }
        }

        void fred2()
        {
            for (int i = 0; i <= 100; i++)
            {
                liste.Add("2222" + " => " + i.ToString());
            }
        }

        void fred3()
        {
            for (int i = 0; i <= 100; i++)
            {
                liste.Add("3333" + " => " + i.ToString());
            }
        }


57 Beiträge seit 2006
vor 17 Jahren

Original von steffen_dec
Hallo,

die Prioritäten sind doch da um diese zu nutzen, warum also nicht??

Tja, weil´s halt nicht deterministisch ist - s.o.
In einer komplexeren Applikation (= viele Threads) können hoch-priore Threads auch zu interessanten Seiteneffekten, wie z.B. "Blockaden", führen. Und die dann aufzuklären - viel Spaß !

2 + 2 = 5 for large values of 2

S
8.746 Beiträge seit 2005
vor 17 Jahren

So isses. Zudem: Was bringt es? Schneller wird davon i.d.R. nix. In jedem Fall ist es kein Mittel zur Ablaufsteuerung.