Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   C# Threads und BackgroundWorker (https://www.delphipraxis.net/110126-threads-und-backgroundworker.html)

Luckie 14. Mär 2008 12:33

Re: Threads und BackgroundWorker
 
Das ist ein Argument. So funktioniert es:
Code:
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
           
            for (int i = 0; i < 100000; i++)
            {
                if (backgroundWorker1.CancellationPending)
                {                   
                    e.Cancel = true;
                }
                else
                {
                    backgroundWorker1.ReportProgress((int)i / 10);
                    Thread.Sleep(0);
                }
            }
        }
Und wie breche ich einen mit der Thread-Klasse erstellten Thread ab? Abort löst eine Exception aus und Suspend lässt ihn nur pausieren. Irgendwie fehlt eine Methode zum terminieren.

Khabarakh 14. Mär 2008 12:55

Re: Threads und BackgroundWorker
 
Zitat:

Zitat von Luckie
Und wie breche ich einen mit der Thread-Klasse erstellten Thread ab? Abort löst eine Exception aus [...]

Wenn es eine ThreadAbortException ist, ist das goldrichtig :zwinker: :
Zitat:

When this method is invoked on a thread, the system throws a ThreadAbortException in the thread to abort it. ThreadAbortException is a special exception that can be caught by application code, but is re-thrown at the end of the catch block unless ResetAbort is called. ResetAbort cancels the request to abort, and prevents the ThreadAbortException from terminating the thread. Unexecuted finally blocks are executed before the thread is aborted.
Damit wird also garantiert, dass der Thread nicht einfach abgewürgt wird (was nicht gerade der BCL-Philosophie entspräche), sondern davor noch alle finally-Blöcke sauber durchlaufen werden. Mit genügend Rechten kann der Thread seinen Abbruch sogar selbst stoppen.

PS: Der Thread ist danach allerdings nicht mehr nutzbar und man benötigt einen neuen. Wenn das öfter geschehen soll, sollte man wohl besser einen ThreadPool-Thread benutzen und in diesem (wie in deinem BackgroundWorker-Code) ein Abbruch-Flag auswerten.

Luckie 14. Mär 2008 13:08

Re: Threads und BackgroundWorker
 
Gut, dann ist Abort doch richtig.

allerdinsg scheint nichts zu passieren:
Code:
        private void btnStop_Click(object sender, EventArgs e)
        {
            if (rbThread.Checked)
            {
                t.Abort();
            }
            else
            {
                backgroundWorker1.CancelAsync();
            }
        }
               

        private void thread1_Event(object sender, EventArgs e)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new EventHandler(thread1_Event));
                }
                else
                {
                    for (int i = 0; i < 100000; i++)
                    {
                        lblStatusText.Text = resManager.GetString("ThreadStatusRunning");
                        this.Update();
                        Thread.Sleep(0);
                    }
                }
            }
            catch (ThreadAbortException tae)
            {
                lblStatusText.Text = resManager.GetString("ThreadStatusFinish");
                this.Update();
            }
        }

        private void ThreadProc()
        {
            try
            {
                thread1_Event(this, null);
            }
            catch (ThreadAbortException tae)
            {
                lblStatusText.Text = resManager.GetString("ThreadStatusFinish");
                this.Update();
            }
        }
Laut Beispiel aus der Hilfe, müsste es aber so aussehen.

Khabarakh 14. Mär 2008 13:22

Re: Threads und BackgroundWorker
 
Habe ich irgendwo oben schon zu deinem ersten Thread-Code geschrieben: Du invokst thread1_Event, also wird deine gesamte Schleife im Hauptthread ausgeführt und dort kann Abort schlecht wirken. Es wird warten, bis thread1_Event beendet ist und erst dann die Exception werfen.

Luckie 14. Mär 2008 13:28

Re: Threads und BackgroundWorker
 
Zitat:

Zitat von Khabarakh
Habe ich irgendwo oben schon zu deinem ersten Thread-Code geschrieben: Du invokst thread1_Event, also wird deine gesamte Schleife im Hauptthread ausgeführt und dort kann Abort schlecht wirken. Es wird warten, bis thread1_Event beendet ist und erst dann die Exception werfen.

Oh, dann habe ich ja gar nicht das was ich wollte. Mist. Wie mache ich es denn richtig?

Code:
private void button1_Click(object sender, EventArgs e)
        {
            if (rbThread.Checked)
            {
                try
                {
                    t = new Thread(ThreadProc);
                    t.Name = "Thead";
                    t.Start();
                }
                catch
                {

                }
            }
            else
            {
                backgroundWorker1.RunWorkerAsync();
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (rbThread.Checked)
            {
                t.Abort();
            }
            else
            {
                backgroundWorker1.CancelAsync();
            }
        }
               

        private void thread1_Event(object sender, EventArgs e)
        {
            try
            {
                if (InvokeRequired)
                {
                    Invoke(new EventHandler(thread1_Event));
                }
                else
                {
                    for (int i = 0; i < 100000; i++)
                    {
                        lblStatusText.Text = resManager.GetString("ThreadStatusRunning");
                        this.Update();
                        Thread.Sleep(0);
                    }
                }
            }
            catch (ThreadAbortException tae)
            {
                lblStatusText.Text = resManager.GetString("ThreadStatusFinish");
                this.Update();
            }
        }

        private void ThreadProc()
        {
            try
            {
                thread1_Event(this, null);
            }
            catch (ThreadAbortException tae)
            {
                lblStatusText.Text = resManager.GetString("ThreadStatusFinish");
                this.Update();
            }
        }

Khabarakh 14. Mär 2008 13:34

Re: Threads und BackgroundWorker
 
Zitat:

Zitat von Luckie
Wie mache ich es denn richtig?

Wie gesagt, ist ziemlich parallel zum BackgroundWorker:
Code:
        void thread1_Event()
        {
            lblStatusText.Text = resManager.GetString("ThreadStatusRunning");
            this.Update();
            Thread.Sleep(0);
        }

        void ThreadProc()
        {
            try
            {
                for (int i = 0; i < 100000; i++)
                {
                    Invoke(new MethodInvoker(thread1_Event)); // ich kann durchaus verstehen, dass nicht jeder anonyme Methoden mag *g*
                } 
            }
            catch (ThreadAbortException tae) // hier würde ich eher finally benutzen
            {
                lblStatusText.Text = resManager.GetString("ThreadStatusFinish"); // und hier sollte es eine Cross-Call-Exception hageln
                this.Update();
            }
        }
Edit: Nach dem dritten Edit übernehme ich lieber keine Verantwortung über die Richtigkeit des Codes ;) .

Luckie 14. Mär 2008 14:07

Re: Threads und BackgroundWorker
 
Jetzt schlägt allerdings die Aktualisierung im finally-Abschnitt fehl:
Zitat:

Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement lblStatusText erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.
:wall:

Elvis 14. Mär 2008 14:09

Re: Threads und BackgroundWorker
 
Zitat:

Zitat von Luckie
Jetzt schlägt allerdings die Aktualisierung im finally-Abschnitt fehl:
Zitat:

Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement lblStatusText erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.
:wall:

Na weil da kein Invoke benutzt wurde.
Du stellst dich auch manchmal an... ;-)

Übrigens musst du nicht so umständlich mit ResourceManagern arbeiten.
Das VS erzeugt autom. statische Eigenschaften für jeden Wert in der Resource Datei, so dass du direkt auf den Namen mit dem richtigen Typ zugreifen kannst.

Luckie 14. Mär 2008 14:22

Re: Threads und BackgroundWorker
 
Ich verzweifele noch mal an diesen delegate und Invoke.
Code:
private void SetStatusText(string Text)
        {
            lblStatusText.Text = Text;
            this.Update();
        }

        void ThreadProc()
        {
            try
            {
                for (int i = 0; i < 100000; i++)
                {
                    Invoke(new MethodInvoker(thread_Event));
                    Thread.Sleep(0);
                }
            }
            finally
            {
                Invoke(SetStatusText(resManager.GetString("ThreadStatusFinish")));              
            }
        }
Will er auch nicht:
Zitat:

The best overloaded method match for 'System.Windows.Forms.Control.Invoke(System.Delega te)' has some invalid arguments

phXql 14. Mär 2008 14:37

Re: Threads und BackgroundWorker
 
Das Problem ist, dass SetStatusText(resManager.GetString("ThreadStatusFi nish")) kein Delegat ist. Bei deinem anderen Invoke-Aufruf hast du das ja auch zuerst in den MethodInvoker-delegaten verpackt.
Du wirst dir also wahrscheinlich für deine SetStatusText(string) einen delegaten basteln müssen, dann die Funktion darin verpacken und dann gehts.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:38 Uhr.
Seite 3 von 4     123 4      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz