C# asynchrones Multithreading

andywawa

Newbie
Registriert
Mai 2011
Beiträge
3
Hallo Forum,
ich habe eine Main-Form mit einem Button, der eine Reihe von Methoden aufruft.
1. Infos sammeln
2. Dateien kopieren
3. Installation
4. andere Installation
5. Scripte ausführen usw.
also "klassisch" top-down. Pkt. 2 (Dateien kopieren) dauert ca. 5 min. daher will ich dem User einen ProgressBar-Balken zeigen, damit er nicht glaubt, das Programm ist abgestürzt (single-Thread=die Form "friert" ein). Es ist essentiell, dass der Pkt. 3 (Installation) auf Pkt. 2 (Kopieren) warten MUSS (sonst kann nicht installiert werden). Auch der Pkt. 4 (andere..) muss auf den Abschluss des Pkt. 3 (Installation) warten.
Wie gesagt, single-Thread kommt nicht in Frage und das Warten auf den Abschluss des Vorgängers bekomme ich nicht im Griff.
@Yuuri hat etwas ähnliches am 11.02.2011 präsentiert (Thread: DateiDownload mit Fortschrittsbalken).
Der Code:

Code:
delegate void ShowProgressDelegate(string target, int totalDigits, int digitsSoFar);
delegate void CalcDelegate(int digits);

void ShowProgress(string target, int totalDigits, int digitsSoFar)
        {
            //sind wir auf dem richtigen Thread??
            if (lblProgressBar.InvokeRequired == false)
            {
                lblProgressBar.Text = target;
                pBar1.Maximum = totalDigits;
                pBar1.Value = digitsSoFar;
            }
            else //Progress zeigen asynchronously...
            {
                ShowProgressDelegate showProgress = new ShowProgressDelegate(ShowProgress);
                //Invoke..
                BeginInvoke(showProgress, new object[] {target,totalDigits,digitsSoFar });
            }

        }

public void AsyncCompleted(IAsyncResult ar)
        {
            AsyncResult result = (AsyncResult)ar;
            try
            {
                ((CalcDelegate)result.AsyncDelegate).EndInvoke(ar);
            }
            catch(Exception ex)
            {
            }
            finally
            {
                WeiterMitPunkt3 //es klappt aber nicht.....ClearAfterCoping();
            }

        }
private void KopierenMitProgressBar(ArrayList myAl)
        {
            //ProgressBar einblenden..
            this.pBar1.Visible = true;
            CalcDelegate calcDel = new CalcDelegate(DoJob);
            calcDel.BeginInvoke((int)myAl.Count, AsyncCompleted, null);
           
        }

        private void DoJob(int digits)
        {
            Object[] myal= myAl.ToArray();
            //ShowProgress
            ShowProgress("Kopieren: ", digits, 0);
            if(digits>0)
            {
                for (int x = 0; x < digits; x++)
                {
                    string input = myal[x].ToString().Substring(0, myal[x].ToString().IndexOf(","));
                    string target = myal[x].ToString().Substring(myal[x].ToString().IndexOf(",") + 1);
                    File.Copy(input, target, true);
                    //Show Progress..
                    ShowProgress("Kopieren: " + target, digits, x);
                }

            }
        }
Ich danke Euch für Hilfe
 
Hi,

schau dir die Backgroundworker mal an. Damit ist eigentlich alles erschlagen, vom ProgressBar über einen eigenen Thread.

VG,
Mad
 
Hallo,
das habe ich auch probiert-ohne Erfolg.
Der BackGroundWorker hat eine Methode "Completed" (oder so), wo ich (dachte mir) den nächsten Step aus der Liste eintrage. Der Worker hat (bei mir zumindest) nicht "gewartet" und das Programm ist einfach weiter (da der Worker die Kontrolle abgibt) zum Pkt. 3 gegangen (Installation) und logischerweise auf die Nase gefallen.
Gruß
 
Backgroundworker!
Wenn er bei dir nicht wie gewünscht lief, dann hast du ihn falsch benutzt ;)
Ich habe auch schon einige Progressbars gebaut und sie funktionierten nach etwas Tüftelei super. Schau nochmal genau ins MSDN und dir dort auch die Beispiele an.
 
Hallo,
danke für den Link, ich versuche jetzt erneut das Problem mit dem BackgroundWorker zu lösen.
Gruß
 
Angenommen du bekommst das mit dem Backgroundworker nicht so hin, wie du es dir vorstellst und möchtest nun das ganze "von Hand" machen ... dann hast du für jede Aktion eigene Threads, die jetzt in einer bestimmten Reihenfolge ablaufen sollen. Du kannst System.Threading.Monitor oder System.Threading.Mutex für die Synchronisation verwenden. Das sind jeweils Objekte mit denen eine Steuerung Threadübergreifend und beim Mutex sogar Prozessübergreifend möglich wird.

Also ich würde eine "Kaskade" der einzelnen Threads aufbauen, am Beispiel von Monitor wäre das ungefähr so:

Code:
    private readonly object syncThread1 = new object();
    private readonly object syncThread2 = new object();
    private readonly object syncThread3 = new object();

    public void StartThreads()
    {
      System.Threading.Thread thread1 = new System.Threading.Thread(new System.Threading.ThreadStart(Thread1));
      thread1.Start();
      System.Threading.Thread thread2 = new System.Threading.Thread(new System.Threading.ThreadStart(Thread2));
      thread2.Start();
      System.Threading.Thread thread3 = new System.Threading.Thread(new System.Threading.ThreadStart(Thread3));
      thread3.Start();
    }

    private void Thread1()
    {
      try
      {
        System.Threading.Monitor.Enter(syncThread1);
        //
        // do something
        //
      }
      finally
      {
        System.Threading.Monitor.Exit(syncThread1);
      }
    }

    private void Thread2()
    {
      try
      {
        System.Threading.Monitor.Enter(syncThread1);
        System.Threading.Monitor.Enter(syncThread2);
        //
        // do something
        //
      }
      finally
      {
        System.Threading.Monitor.Exit(syncThread2);
        System.Threading.Monitor.Exit(syncThread1);
      }
    }

    private void Thread3()
    {
      try
      {
        System.Threading.Monitor.Enter(syncThread1);
        System.Threading.Monitor.Enter(syncThread2);
        System.Threading.Monitor.Enter(syncThread3);
        //
        // do something
        //
      }
      finally
      {
        System.Threading.Monitor.Exit(syncThread3);
        System.Threading.Monitor.Exit(syncThread2);
        System.Threading.Monitor.Exit(syncThread1);
      }
    }

Alternativ könntest du auch das Ganze umdrehen, d.h. den Progressbar als Splashfenster in einem eigenen Thread laufen lassen und deine eigentlichen Aktionen weiterhin im Hauptthread synchron nacheinander ausführen.

Also es gibt da viele Wege die nach Rom führen.

Viel Spaß beim Coden
Rossibaer
 
Zuletzt bearbeitet:
Zurück
Oben