Multi Threading Problem

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von Noim.

    Multi Threading Problem

    Hallo Leute,

    da ich ja wieder weiter Arbeite an meinem Projekt "Katastrophale Haussteuerung die irgendwie funktionieren wird... mit viel glück" bin ich wieder auf ein Problem gestoßen. Mein Plan ist es die Methode homeputer_ChangedObjects jede zweite Sekunden ausführen zu lassen, um dann, wenn ich irgendwann so weit bin, die Values in einer Datenbank zu aktualisieren. Da dies aber natürlich nicht auf dem Main Thread laufen soll, habe ich mit einem Worker angefangen. Dieser startet sofort nachdem homeputer_InitDLL ausgeführt wurde. Doch das einzige was ich im Moment hin bekommen ist, das bei homeputer_ChangedObjects eine Exception ausgeführt wird. Dieses Exception wird hierbei ausgelöst:


    #EDIT: Der ExternalException.ErrorCode lautet übrigens -2147467259
    Ich denke es hat was damit zu tuen, das die DoWork Methode natürlich nicht auf dem MainThread ausgeführt wird, aber homeputer_InitDLL schon. Nur Multi Threading habe ich noch nie wirklich gemacht (So wie vieles halt xD).
    Und MethodInvoker geht denke ich nur bei einer WindowsForms, wie ich es bei meiner LogInvoke Methode getan habe.
    Hier aber erstmal mein Code:

    C#-Quellcode

    1. //Die Methoden der DLL
    2. [DllImport("homeputer.dll")]
    3. private static extern int homeputer_InitDLL();
    4. [DllImport("homeputer.dll")]
    5. private static extern int homeputer_ChangedObjects(StringBuilder s);
    6. [DllImport("homeputer.dll")]
    7. private static extern int homeputer_SetObjValName(String Objektname, String Objektwert);
    8. [DllImport("homeputer.dll")]
    9. private static extern int homeputer_ChangeCount();
    10. [DllImport("homeputer.dll")]
    11. private static extern int homeputer_SetWindowHandle(IntPtr Handl);
    12. [DllImport("homeputer.dll")]
    13. private static extern int homeputer_GetObjIdx(int Index, String Objektname, String Objektwert);
    14. [DllImport("homeputer.dll")]
    15. private static extern int homeputer_GetObjValName(String Objektname, String Objektwert);
    16. [DllImport("kernel32", SetLastError = true)]
    17. static extern IntPtr LoadLibrary(string lpFileName);
    18. static bool CheckLibrary(string fileName)
    19. {
    20. return LoadLibrary(fileName) == IntPtr.Zero;
    21. }
    22. public static MainForm mf;
    23. public static RefreshWorker rw;
    24. public static Thread rfwt;
    25. public static bool init()
    26. {
    27. try
    28. {
    29. int i = homeputer_InitDLL(); //Wichtig, das die DLL funktioniert.
    30. if (i == 1)
    31. {
    32. rw = new RefreshWorker();
    33. rw.mff = mf;
    34. rfwt = new Thread(rw.DoWork);
    35. rfwt.Start();
    36. }
    37. if (i == 1) return true;
    38. return false;
    39. }
    40. catch (System.DllNotFoundException)
    41. {
    42. mf.log("Can not find homeputer.dll");
    43. }
    44. return false;
    45. }
    46. public static void p() //Normale Methode, wenn ich auf einen Button in der Forms klicke, diese Funktioniert einwandfrei.
    47. {
    48. StringBuilder s = new StringBuilder(); //I am so sorry jvbsl, ich habe deine Methode noch nicht eingefügt :D
    49. try
    50. {
    51. homeputer_ChangedObjects(s);
    52. }
    53. catch (Exception ee) //Damit, wenn ein Fehler kommt sich das Programm nicht gleich beendet.
    54. {
    55. mf.logInvoke("Ex P: " + ee.StackTrace);
    56. }
    57. string sst = s.ToString();
    58. string[] sstt = sst.Split(';');
    59. for (int i = 0; i < sstt.Count() - 1; i++)
    60. {
    61. mf.log(i + ": " + sstt[i]);
    62. }
    63. }
    64. public static void stopRefreshWorker()
    65. {
    66. //Damit der Thread nach dem beenden nicht weiter läuft. Hatte damit schon große Probleme, weil ich die Datei nicht mehr ersetzen konnte und den Prozess nicht finden konnte. Deshalb wird er hier safe beendet.
    67. rw?.RequestStop();
    68. rfwt?.Join();
    69. }
    70. public class RefreshWorker
    71. {
    72. public void DoWork()
    73. {
    74. //homeputer_InitDLL();
    75. while (!_shouldStop)
    76. {
    77. mff.logInvoke("Run Thread"); //mff.logInvoke schreibt einfach die Log Daten in eine ListBox in der MainForm
    78. StringBuilder s = new StringBuilder();
    79. try
    80. {
    81. homeputer_ChangedObjects(s); //Hier entsteht die Exception.
    82. }
    83. catch (Exception ee)
    84. {
    85. //mff.logInvoke("Ex: " + ee.Data);
    86. mff.log("==> " + ee.ToString());
    87. RequestStop();
    88. }
    89. string sst = s.ToString();
    90. string[] sstt = sst.Split(';');
    91. for (int i = 0; i < sstt.Count() - 1; i++)
    92. {
    93. mff.logInvoke(i + ": " + sstt[i]);
    94. }
    95. Thread.Sleep(2000);
    96. }
    97. }
    98. public void RequestStop()
    99. {
    100. _shouldStop = true;
    101. }
    102. private volatile bool _shouldStop;
    103. public MainForm mff; //Um auf die MainForm zu greifen zu können.
    104. }


    Ich habe versucht meinen Code mit Kommentaren zu erklären, zwar nicht alles, doch genug damit man das eigentliche versteht. Wenn ich noch weitere Daten der Exception posten soll, dann sagt mir bescheid.
    Ich denke ich bin einfach noch nicht fit genug im Thema Threads, und deshalb entsteht der Fehler.

    MFG Nils X/

    #EDIT: Ich bin etwas weiter gekommen. Ich habe es dann doch irgendwie mit MethodInvoke versucht. Also das Programm läuft gerade die ganze Zeit ohne Fehler. Sauber ist es nicht was ich da gemacht habe. Ich musste dann doch den Code von @jvbsl intigrieren, da anscheint dann wirklich ein Memory Fehler entsteht. Ich habe jetzt mit tausend try catch Blöcken gearbeitet.
    Das Resultat meiner bisherigen Arbeit:
    Homeputer.cs
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Linq;
    5. using System.Runtime.CompilerServices;
    6. using System.Runtime.InteropServices;
    7. using System.Text;
    8. using System.Threading;
    9. using System.Threading.Tasks;
    10. namespace Socket_Homeputer
    11. {
    12. class Homeputer
    13. {
    14. [DllImport("homeputer.dll")]
    15. private static extern int homeputer_InitDLL();
    16. [DllImport("homeputer.dll")]
    17. private static extern int homeputer_ChangedObjects(StringBuilder s);
    18. [DllImport("homeputer.dll")]
    19. private static extern int homeputer_SetObjValName(StringBuilder Objektname, StringBuilder Objektwert);
    20. [DllImport("homeputer.dll")]
    21. private static extern int homeputer_ChangeCount();
    22. [DllImport("homeputer.dll")]
    23. private static extern int homeputer_SetWindowHandle(IntPtr Handl);
    24. [DllImport("homeputer.dll")]
    25. private static extern int homeputer_GetObjIdx(int Index, String Objektname, String Objektwert);
    26. [DllImport("homeputer.dll")]
    27. private static extern int homeputer_GetObjValName(String Objektname, String Objektwert);
    28. [DllImport("kernel32", SetLastError = true)]
    29. static extern IntPtr LoadLibrary(string lpFileName);
    30. static bool CheckLibrary(string fileName)
    31. {
    32. return LoadLibrary(fileName) == IntPtr.Zero;
    33. }
    34. public static MainForm mf;
    35. public static RefreshWorker rw;
    36. public static Thread rfwt;
    37. public static int trys = 0;
    38. public static bool init()
    39. {
    40. try
    41. {
    42. int i = initDLL();
    43. Thread.Sleep(500);
    44. StringBuilder objname = new StringBuilder();
    45. objname.Append("Licht_SZDecke");
    46. StringBuilder objwert = new StringBuilder();
    47. objwert.Append("an");
    48. mf.log(homeputer_SetObjValName(objname, objwert).ToString());
    49. if (i == 1)
    50. {
    51. rw = new RefreshWorker();
    52. rw.mff = mf;
    53. rfwt = new Thread(rw.DoWork);
    54. rfwt.Start();
    55. }
    56. if (i == 1) return true;
    57. return false;
    58. }
    59. catch (System.DllNotFoundException)
    60. {
    61. mf.log("Can not find homeputer.dll");
    62. }
    63. return false;
    64. }
    65. public static int initDLL()
    66. {
    67. trys++;
    68. int i = homeputer_InitDLL();
    69. if (i == 0 && trys < 4)
    70. {
    71. return initDLL();
    72. } else
    73. {
    74. return i;
    75. }
    76. }
    77. public static void p()
    78. {
    79. try
    80. {
    81. homeputer_InitDLL();
    82. try
    83. {
    84. int size = homeputer_ChangeCount() * 32;
    85. StringBuilder s = new StringBuilder(size);
    86. try
    87. {
    88. homeputer_ChangedObjects(s);
    89. string sst = s.ToString();
    90. string[] sstt = sst.Split(';');
    91. for (int i = 0; i < sstt.Count() - 1; i++)
    92. {
    93. mf.log(i + ": " + sstt[i]);
    94. }
    95. }
    96. catch (Exception ee)
    97. {
    98. mf.log("Ex P: " + ee.ToString() + " | " + ee.HResult);
    99. }
    100. } catch (Exception ee)
    101. {
    102. mf.log(ee.ToString());
    103. }
    104. } catch (Exception ee)
    105. {
    106. mf.log(ee.ToString());
    107. }
    108. }
    109. public static void stopRefreshWorker()
    110. {
    111. rw?.RequestStop();
    112. rfwt?.Join();
    113. }
    114. public class RefreshWorker
    115. {
    116. public void DoWork()
    117. {
    118. //homeputer_InitDLL();
    119. //Thread.Sleep(1000);
    120. while (!_shouldStop)
    121. {
    122. try
    123. {
    124. /*
    125. mff.logInvoke("Run Thread");
    126. StringBuilder s = new StringBuilder();
    127. homeputer_ChangedObjects(s);
    128. string sst = s.ToString();
    129. string[] sstt = sst.Split(';');
    130. for (int i = 0; i < sstt.Count() - 1; i++)
    131. {
    132. mff.logInvoke(i + ": " + sstt[i]);
    133. }*/
    134. //homeputer_InitDLL();
    135. mff.tryP();
    136. }
    137. catch (Exception ee)
    138. {
    139. //mff.logInvoke("Ex: " + ee.Data);
    140. mff.logInvoke("==> " + ee.ToString());
    141. //RequestStop();
    142. //Thread.CurrentThread.Join();
    143. }
    144. Thread.Sleep(2000);
    145. }
    146. }
    147. public void RequestStop()
    148. {
    149. _shouldStop = true;
    150. }
    151. private volatile bool _shouldStop;
    152. public MainForm mff;
    153. }
    154. }
    155. }


    MainForm.cs
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Runtime.CompilerServices;
    8. using System.Security.Cryptography.X509Certificates;
    9. using System.Text;
    10. using System.Threading;
    11. using System.Threading.Tasks;
    12. using System.Windows.Forms;
    13. using System.Windows.Forms.VisualStyles;
    14. using MaterialSkin;
    15. using MaterialSkin.Controls;
    16. namespace Socket_Homeputer
    17. {
    18. public partial class MainForm : MaterialForm
    19. {
    20. public MainForm()
    21. {
    22. InitializeComponent();
    23. Homeputer.mf = this;
    24. var materialSkinManager = MaterialSkinManager.Instance;
    25. materialSkinManager.AddFormToManage(this);
    26. materialSkinManager.Theme = MaterialSkinManager.Themes.LIGHT;
    27. materialSkinManager.ColorScheme = new ColorScheme(Primary.BlueGrey800, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE);
    28. logBox.Items.Add("[" + DateTime.Now.ToString() + "] Windows Form initialized.");
    29. bool init = Homeputer.init();
    30. log(init ? "Homeputer.dll was initialized." : "Homeputer.dll was not initialized.");
    31. if (!init) getChObj.Enabled = false;
    32. }
    33. public void log(String m)
    34. {
    35. logBox.Items.Add("[" + DateTime.Now.ToString() + "] " + m);
    36. }
    37. public void logInvoke(String m)
    38. {
    39. MethodInvoker mi = delegate {
    40. logBox.Items.Add("[" + DateTime.Now.ToString() + "] " + m);
    41. };
    42. if (InvokeRequired)
    43. this.Invoke(mi);
    44. }
    45. public void tryP()
    46. {
    47. Homeputer.p();
    48. }
    49. private void getChObj_Click(object sender, EventArgs e)
    50. {
    51. Homeputer.p();
    52. }
    53. }
    54. }



    Am besten wären paar Empfehlungen wie ich dies verbessern kann. Wie gesagt eigentlich habe ich die Sch***e nur mit mehr Sch***e verstärkt :D.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Noim“ ()

    Noim schrieb:

    Am besten wären paar Empfehlungen wie ich dies verbessern kann. Wie gesagt eigentlich habe ich die Sch***e nur mit mehr Sch***e verstärkt :D.
    Wenn dem wirklich so ist, dann ist der beste Rat, den man dir geben kann: Machs nochmal von vorne, mit einem tragfähigen Konzept, und geeigneten Technologien.

    Zum Code kann ich nix sagen, ich weiß nicht was der machen soll, und v.a. kenne ich die homeputer.dll nicht.
    @ErfinderDesRades: Zu der homeputer.dll, schau mal hier vorbei contronics.de/download/homeputerCLBeschreibung.pdf
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell