Autor Beitrag
sentropie
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Fr 08.10.10 12:57 
Hallo,

ich lerne momentan C# und versuche mich an einem WindowsForms-Programm, in welchem ich mit Threads herumspiele. Im Prinzip besteht das Fenster aus einem Button und zwei Textboxen. Beim Klick auf den Button soll in beiden Textboxen gleichzeitig ein Zähler hochlaufen. Bei mir passiert das jedoch schön nacheinander - auch wenn es zufällig erscheint, in welcher Box begonnen wird.

Hier kommt der Code. Ich freue mich auf Ratschläge.

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Forms_Threading
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private int max = 10000;

        private void fkt1()
        {
            MethodInvoker m1 = delegate
            {
                for (int j = 0; j <= max; j++)
                {
                    textBox1.Text = j.ToString();               
                    textBox1.Refresh();                    
                }
            };

            Invoke(m1);
        }

        private void fkt2()
        {
            MethodInvoker m2 = delegate
            {
                for (int i = 0; i <= max; i++)
                {
                    textBox2.Text = i.ToString();
                    textBox2.Refresh();
                }
            };

            Invoke(m2);                       
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "";
            textBox2.Text = "";

           
            Thread t1 = new Thread(fkt1);
            Thread t2 = new Thread(fkt2);
            t1.IsBackground = true;
            t2.IsBackground = true;
            t1.Start();
            t2.Start();                    
        }
    }
}
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 08.10.10 13:47 
Du "invoke"st ja auch jeweils die ganze Schleife.
Du mußt nur den GUI-Teil (d.h. die TextBox-Methoden) per Invoke aufrufen.

Falls du schon mit VS 2010 und .NET 4.0 arbeitest, kannst du dir mal die "Task Parallel Library" (TPL) anschauen, s.a. www.c-sharp-forum.de....php?p=604486#604486

Für diesen Beitrag haben gedankt: sentropie
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Fr 08.10.10 14:00 
Und selbst dann laufen die Threads nicht gleichzeitig. Rechenzeit gibts nur einmal :) So dass mal thread1 und dann wieder thread2 dran ist.

Mit dem BackgroundWorker kannst du es ein bisschen (ressourcemässig) schlanker gestalten. Darüber hinaus beenden sich die BackgroundWorker wenn sich der Hauptthread beendet.

Besser wäre auch, wenn du nicht fkt1 und fkt2 machst, sondern das zu ändernde TextBox-Control der funktion mitgibst (z.B. hier).

Gruß
Implementation
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 33
Erhaltene Danke: 2

Parabola, Trisquel GNU/linux-libre
FPC, GCC
BeitragVerfasst: Fr 08.10.10 14:26 
user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Und selbst dann laufen die Threads nicht gleichzeitig. Rechenzeit gibts nur einmal :) So dass mal thread1 und dann wieder thread2 dran ist.

Und was ist wenn man mehrere CPU's hat?
Oder eine CPU mit mehreren Kernen?
Dann läuft's gleichzeitig :wink:

_________________
Free as in Freedom!
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Fr 08.10.10 14:28 
Nein ;p

Weil es immer noch der gleiche Prozess ist .. und dieser läuft immer nur auf einem CPU.

Dann brauchst du schon Parallel Framework ;p
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Fr 08.10.10 15:29 
user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Weil es immer noch der gleiche Prozess ist .. und dieser läuft immer nur auf einem CPU.
Äh, nein. Jeder Thread kann pro Time Slice auf jedem beliebigen Kern laufen, solange keine Affinity festgelegt ist.

user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Dann brauchst du schon Parallel Framework ;p
Was natürlich auch nur einen Prozess benutzt und darin einen geschönten Threadpool ;) .

@user profile iconsentropie: :welcome: !

_________________
>λ=
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Fr 08.10.10 15:39 
gefährliches Halbwissen ...

Da hab ich den Anlass doch gleich mal genutzt um MSDN (Threads und Threading) zu lesen.

Zitat:
Dies ist bei Systemen mit mehreren Prozessoren auch tatsächlich der Fall, bei denen die ausführbaren Threads unter den verfügbaren Prozessoren aufgeteilt werden.


Zitat:
Ohne weitere Veränderungen würde dieselbe Anwendung auf einem Computer mit mehreren Prozessoren noch weitaus bessere Ergebnisse liefern.


Na dann bin ich ja schon voll MultiCore unterwegs ;)
sentropie Threadstarter
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Fr 08.10.10 18:21 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Du "invoke"st ja auch jeweils die ganze Schleife.
Du mußt nur den GUI-Teil (d.h. die TextBox-Methoden) per Invoke aufrufen.

Falls du schon mit VS 2010 und .NET 4.0 arbeitest, kannst du dir mal die "Task Parallel Library" (TPL) anschauen, s.a. www.c-sharp-forum.de....php?p=604486#604486

Danke, nun klappt das schon mal.

Bei Gelegenheit werde ich mir mal die 4.0er Version anschauen. Aber wenn es auch "klassisch" geht, warum nicht? Daher habe ich erstmal so gemacht.

user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
[...]
Mit dem BackgroundWorker kannst du es ein bisschen (ressourcemässig) schlanker gestalten. Darüber hinaus beenden sich die BackgroundWorker wenn sich der Hauptthread beendet.

Besser wäre auch, wenn du nicht fkt1 und fkt2 machst, sondern das zu ändernde TextBox-Control der funktion mitgibst (z.B. [url=dotnet-snippets.de/d...83.aspx]hier[/url]).

BackgroundWorker sollte ich mir in der Tat einmal genauer anschauen. Allerdings fand ich das auf den ersten Blick nicht so leicht verständlich. Aber mal gucken.
Alles in eine Funktion wäre eine weitere Verbesserungsmöglichkeit. Auch etwas für die nahe Zukunft. :)

@user profile iconKha: Danke. :)

--------------------------------------

Jetzt, wo diese Sache läuft, möchte ich einen Schritt weitergehen. Ich habe einen Button und ein Textfeld hinzugefügt. Ich möchte nun, dass in dem Textfeld eine Zahl hochgezählt wird - und zwar bei jedem Klick +1. Ich bin jetzt so weit, dass die Klicks "registriert" werden, aber das Resultat sehe ich erst, nachdem die beiden Zähler-Threads fertig sind. (Also da steht z.B. eine 1, ich klick 3x und NACH dem Hochzählen erscheint eine 4. Das soll jedoch mehr oder weniger unmittelbar passieren.)

Das wäre der Button:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
private void button2_Click(object sender, EventArgs e)
{
    int zahl = Convert.ToInt32(textBox3.Text) + 1;
    textBox3.Text = zahl.ToString();
}


Ich habe da auch schon (erfolglos) probiert, mit einem weiteren Thread anzukommen, aber das veränderte alles entweder zum schlechteren oder änderte nichts. Ich habe da auch ein Verständnisproblem. Thread 1 und 2 (der Hauptthread sei 0) erzeuge ich ja in der Click-Methode des Button1. Der weiß natürlich nichts von einem Thread im 2. Button (und umgekehrt). In einer Konsolenanwendung würde ich die Threads "ja einfach" in der main-Funktion erzeugen, aber wie muss ich hier vorgehen? Wo erzeugt man da richtigerweise die Threads?
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Fr 08.10.10 19:25 
user profile iconsentropie hat folgendes geschrieben Zum zitierten Posting springen:
Ich bin jetzt so weit, dass die Klicks "registriert" werden [...]
Wenn ich das bei mir ausprobiere, wird auch der Klick erst am Ende "visuell registriert". Und das liegt daran, dass dein Beispiel einfach noch nicht wirklich etwas mit Threads zu tun hat ;) . Da in den Nebenthreads nichts gearbeitet wird, nicht einmal ein Thread.Sleep, sind sie die ganze Zeit am Invoken und du hast den gleichen Effekt, als ob du die Schleifen im GUI-Thread ausführen würdest - es werden keine Events abgearbeitet.

_________________
>λ=