none
Warum funktioniert mein MethodInvoker nicht? RRS feed

  • Frage

  • Hi Zusammen,

    habe eine kurze aber für mich wichtige Verständnisfrage:

    Warum funktioniert folgend mein MethodInvoker nicht?

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace GPI13_4_Fibonacci
    {
        public partial class frmFibonacci : Form
        {
            long[] werte = new long[93];
            long wert;
            const string berechnen = "Berechnen";
    
            public frmFibonacci()
            {
                InitializeComponent();
            }
    
            private void cmdSchließen_Click(object sender, EventArgs e)
            {
                Environment.Exit(0);
            }
    
            private void cmdBerechnen_Click(object sender, EventArgs e)
            {
                Thread t2 = new Thread(new ThreadStart(this.ZahlAusgeben));
                if (cmdBerechnen.Text == berechnen)
                {
                    cmdBerechnen.Text = "Abbrechen";
                    if (long.TryParse(tbEingabe.Text, out wert) && long.Parse(tbEingabe.Text) > 0
                        && long.Parse(tbEingabe.Text) < 93)
                        t2.Start();
                    else
                        MessageBox.Show("Ungültige Eingabe!", "Fehler!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    cmdBerechnen.Text = berechnen;
                    t2.Abort();
                }
                tbEingabe.SelectAll();
                tbEingabe.Focus();
            }
    
            public long fibZahl(long z)
            {
                lock (this)
                {
                    if (z == 1 || z == 2)
                    {
                        werte[0] = 1;
                        werte[1] = 1;
                        return 1;
                    }
                    else
                        werte[z - 1] = fibZahl(z - 1) + fibZahl(z - 2);
                    return werte[z - 1];
                }
            }
    
            public void ZahlErrechnen()
            {
                long wert = fibZahl(92);
            }
    
            public void ZahlAusgeben()
            {
                while (true)
                {
                    if (werte[wert] != 0)
                    {
                        MessageBox.Show("Die " + wert + ". Fibonacci-Zahl lautet: " + werte[wert], "Fertig!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                        MethodInvoker buttonUpdate = delegate
                        {
                            cmdBerechnen.Text = berechnen;
                        };
                        Invoke(buttonUpdate);
                        break;
                    }
                }
            }
    
            private void frmFibonacci_Load(object sender, EventArgs e)
            {
                Thread t = new Thread(new ThreadStart(this.ZahlErrechnen));
                t.Start();
            }
    
            private void frmFibonacci_FormClosing(object sender, FormClosingEventArgs e)
            {
                Environment.Exit(0);
            }
        }
    }
    

    Freue mich sehr auf eure Antworten.

    Gruß

    Matze

    Dienstag, 14. Juli 2015 18:31

Antworten

  • Hi Iso7,
    die Methode "ZahlErrechnen" terminiert bei mir nicht wegen der Rekursion "werte[z -1] = fibZahl(z -1) + fibZahl(z -2);". Damit die Methode terminiert, sollte sie z.B. so aussehen:

        public long fibZahl(long z)
        {
          lock (this)
          {
            if (z == 1 || z == 2)
            {
              werte[0] = 1;
              werte[1] = 1;
              return 1;
            }
            else
              if (werte[z - 2] == 0 || werte[z - 3] == 0)
                werte[z - 1] = fibZahl(z - 1) + fibZahl(z - 2);
              else
                werte[z - 1] = werte[z - 2] + werte[z - 3];
            return werte[z - 1];
          }
        }

    Einfacher geht es aber so:

        public long fibZahl(long z)
        {
          if (z > 1) werte[z - 1] = fibZahl(z - 1);
          if (z == 1 || z == 2) return 1;
          return werte[z - 1] + werte[z - 2];
        }

    wobei noch zu klären ist, ab der erste Wert im Array werte auf Index 0 oder Index 1 steht. Im obigen Beispiel steht er auf Index 1.

       

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks


    • Bearbeitet Peter Fleischer Mittwoch, 15. Juli 2015 06:26 verkürzte rekursive Methode
    • Als Antwort markiert Idhaun Donnerstag, 16. Juli 2015 09:03
    Mittwoch, 15. Juli 2015 04:06
  • Hallo Matze,

    weil Du den Text von Schaltfläche änderst, versuch mal die Invoke-Methode von Button aufzurufen:

    cmdBerechnen.Invoke(buttonUpdate);

    oder

    cmdBerechnen.BeginInvoke(buttonUpdate);

    Ich würde Dir empfehlen die Methode fibZahl zu überarbeiten (wie Peter vorgeschlagen hat). Ich vermute, dass der Prozess stark mit der Berechnung von Fibonacci Zahlen beschäftigt ist und deswegen der Text der Schaltfläche wird nicht geändert.


    Grüße,






    • Als Antwort markiert Idhaun Donnerstag, 16. Juli 2015 09:03
    • Bearbeitet Iso7 Donnerstag, 16. Juli 2015 09:37
    Donnerstag, 16. Juli 2015 08:28

Alle Antworten

  • Hi,
    die Rekursion in fibZahl ist unendlich. Die Funktion hat kein Ende. Das solltest Du erst einmal ändern, z.B. mit einem Testprojekt und Test der Funktion.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 14. Juli 2015 20:07
  • Hallo,

    @Peter
    ich sehe keine unendliche Schleife in der Methode fibZahl. Bei z ==2 wird die Rekursion beendet.
    Aber es gibt einen Deadlock in dieser Methode (wegen lock(this)) und fehlt eine Prüfung, ob z <=0 ist. 

    @Matze
     Wenn das Array werte[] wegen Deadlock in fibZahl(..) mit den Werten nicht gefüllt wird, dann hast Du unendliche Schleife in der Methode ZahlAusgeben().

    Was ist cmdBerechnen? Wird der MessageBox angezeigt?

    Änderung:

    Es gibt keinen Deadlock bei diese Rekursion. Bei lock werden nur die andere Thread blockiert. Mein Fehler.



    Grüße

     
    • Bearbeitet Iso7 Donnerstag, 16. Juli 2015 08:56
    Dienstag, 14. Juli 2015 22:25
  • Hi Iso7,
    die Methode "ZahlErrechnen" terminiert bei mir nicht wegen der Rekursion "werte[z -1] = fibZahl(z -1) + fibZahl(z -2);". Damit die Methode terminiert, sollte sie z.B. so aussehen:

        public long fibZahl(long z)
        {
          lock (this)
          {
            if (z == 1 || z == 2)
            {
              werte[0] = 1;
              werte[1] = 1;
              return 1;
            }
            else
              if (werte[z - 2] == 0 || werte[z - 3] == 0)
                werte[z - 1] = fibZahl(z - 1) + fibZahl(z - 2);
              else
                werte[z - 1] = werte[z - 2] + werte[z - 3];
            return werte[z - 1];
          }
        }

    Einfacher geht es aber so:

        public long fibZahl(long z)
        {
          if (z > 1) werte[z - 1] = fibZahl(z - 1);
          if (z == 1 || z == 2) return 1;
          return werte[z - 1] + werte[z - 2];
        }

    wobei noch zu klären ist, ab der erste Wert im Array werte auf Index 0 oder Index 1 steht. Im obigen Beispiel steht er auf Index 1.

       

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks


    • Bearbeitet Peter Fleischer Mittwoch, 15. Juli 2015 06:26 verkürzte rekursive Methode
    • Als Antwort markiert Idhaun Donnerstag, 16. Juli 2015 09:03
    Mittwoch, 15. Juli 2015 04:06
  • Die Methode ZahlErrechnen hat einen Fehler. Der Wert wert soll nicht wiedererklärt sein.

           public void ZahlErrechnen()
            {
                wert = fibZahl(92); // Entfern den Wort long.
            }

    Mittwoch, 15. Juli 2015 04:18
  • Hi,

    cmdBerechnen ist ein Button. Die MessageBox wird angezeigt.

    War auch schon mit dem Debugger in der Methode. Der MethodInvoker wird durch den Debugger zwar aufgerufen aber er macht irgendwie gar nichts.

    Gruß

    Matze

    Mittwoch, 15. Juli 2015 08:18
  • Hallo Peter,

    ja, die Implementierung in der fibZahl(..) von Matze ist keine gute Lösung für die Fibonacci- Berechnung. Der Wert wird immer neu berechnet anstatt  den Wert, der schon berechnet wurde,  aus dem Array zu nehmen. Das führt zu der langen Berechnungszeit oder sogar zum Stack-Overflow. Ich habe extra diese Methode fibZahl(..) bei mir ausprobiert und die Methode wird bei mir terminiert. Ich habe kleine Werte (10-30) für den Test genommen. Mit dem Wert 93 dauert die Berechnung zu lange.

     

    Grüße



    • Bearbeitet Iso7 Mittwoch, 15. Juli 2015 09:19
    Mittwoch, 15. Juli 2015 08:18
  • Hi Ante,

    Jo Danke das ist korrekt. Ich hatte die Variable "wert" zuvor innerhalb einer Methode deklariert weshalb ich sie in dieser Methode zunächst erneut deklarieren musste. Das fällt jetzt aber durch die globale Deklaration weg. Hab ich nicht aufgepasst.

    @alle: Ich werde mich heute nachmittag ca 15 Uhr MESZ Uhr nochmal dran setzen und eure vorschläge testen. Auf jeden Fall schon einmal vielen Dank vorab für die große Resonanz.

    Ich melde mich noch mal

    Gruß

    Matze

    Mittwoch, 15. Juli 2015 08:22
  • Die Methode ZahlErrechnen hat einen Fehler. Der Wert wert soll nicht wiedererklärt sein.

           public void ZahlErrechnen()
            {
                wert = fibZahl(92); // Entfern den Wort long.
            }

    Wenn man das Programm so ändert, dann muss auch die Mathode ZahlAusgeben() bearbeitet werden. Sonst kriegt man eine IndexOutOfRangeException.   



    • Bearbeitet Iso7 Mittwoch, 15. Juli 2015 08:25
    Mittwoch, 15. Juli 2015 08:25
  • Hi Iso7,
    im vorliegenden Programm wird ein Array "werte" im Load-Ereignis erstellt, aus dem die Zahlen gelesen werden können. Es ist nicht notwendig, jedes Mal neu zu berechnen, was im Programm auch nicht gemacht wird.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks

    Mittwoch, 15. Juli 2015 08:34
  • Ah, du hast rechts, Iso7. Mein Fehler.
    Mittwoch, 15. Juli 2015 08:44
  • Hallo Peter,

    unter „keine gute Lösung“ habe ich die Implementierung der Fibonacci Berechnung  in der Methode fibZahl(..) von Matze gemeint.

     

    Grüße

    Mittwoch, 15. Juli 2015 09:08
  • Hi zusammen,

    vielleicht noch eine kurze Info:

    Rekursive Aufrufe halte ich auch für unsinnig. Allerdings ist das laut Aufgabenstellung so vorgesehen um eine längere abbrechbare Rechenlaufzeit zu erhalten.

    Der Aufruf im Berechnungs-Thread muss nicht zwingend Terminieren. Das Widerspricht zwar den Regeln eines Algorithmus aber ist ebenso vorgegeben. Es Terminiert praktisch mit beendigung des Programmes Environment.Exit(0)

    Ich hatte jetzt gedacht meins Terminiert bei der 92. Fibonacci-Zahl. Das ist die Zahl, die noch in den Typ Long passt.

    Mich würde nach wie vor hauptsächlich interessieren warum mein MethodInvoker nicht funktioniert.

    Leider bin ich noch nicht am heimischen PC und ich bekomme von hier auch keine VPN hin sodass ich noch nicht am Quellcode arbeiten kann. Aber schon mal vielen Dank für eure Antworten.

    Ich bin überwältigt wie groß das Interesse an der Lösung dieser Aufgabenstellung ist :-)

    Gruß

    Matze

    Mittwoch, 15. Juli 2015 10:08
  • Hallo Matze,

    wo wird die Form frmFibonacci erzeugt? In Main Thread?

    Grüße

    Mittwoch, 15. Juli 2015 12:20
  • Japp
    Mittwoch, 15. Juli 2015 13:00
  • Kann mir mit dem MethodInvoker niemand helfen?
    Donnerstag, 16. Juli 2015 08:18
  • Hallo Matze,

    weil Du den Text von Schaltfläche änderst, versuch mal die Invoke-Methode von Button aufzurufen:

    cmdBerechnen.Invoke(buttonUpdate);

    oder

    cmdBerechnen.BeginInvoke(buttonUpdate);

    Ich würde Dir empfehlen die Methode fibZahl zu überarbeiten (wie Peter vorgeschlagen hat). Ich vermute, dass der Prozess stark mit der Berechnung von Fibonacci Zahlen beschäftigt ist und deswegen der Text der Schaltfläche wird nicht geändert.


    Grüße,






    • Als Antwort markiert Idhaun Donnerstag, 16. Juli 2015 09:03
    • Bearbeitet Iso7 Donnerstag, 16. Juli 2015 09:37
    Donnerstag, 16. Juli 2015 08:28
  • Hi zusammen,

    Okay Super. Hat geklappt.

    Vielen Dank an alle beteiligten.

    Gruß

    Matze

    Donnerstag, 16. Juli 2015 09:03