Autor |
Beitrag |
meisse
      
Beiträge: 25
|
Verfasst: Do 14.07.11 12:40
Hallo zusammen
In meiner Applikation will ich Daten abspeichern. Beim speichern öffnet sich ein modaler Dialog, welcher den Verlauf des Speichern grafisch
in einer ProgressBar darstellt. Das speichern passiert in einem separaten Thread. Dieser ruft dann eine Methode aus einer C++ DLL auf.
C#-Quelltext 1:
| InputDataSource.GetRawDataStream(blk, startSample + offset, (int)toGo, bufferSize, streamManager); |
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| try { lock (DllMutex) { if (RawDataStream != null) { errorCode = NativeMethods.TPC_GetRawDataStream(deviceIx, boardAddress, inputNumber, blockNumber, measurementNumber, (ulong)dataStart, (int)dataLength, (int)bufferSize, RawDataStream); } else { errorCode = ErrorCode.RawDataStreamNotDefined; } } } finally {
} |
C#-Quelltext 1: 2: 3: 4: 5:
| [DllImport(dllName)] public static extern ErrorCode TPC_GetRawDataStream(int deviceIx, int boardAddress, int inputNumber, int blockNumber, int measurementNumber, UInt64 dataStart, int dataLength, int bufferSize, TPC_DataStreamCallback callback); |
Also die TPC_GetRawDataStream methode wäre der Aufruf der C++ Methode. Solange diese Methode benötigt um die Daten anzuforden, solange ist mein Dialog
komplett gesperrt. Ich frage mich aber warum dies so ist. Wieso sollte dieser externe Aufruf den GUI Thread blockieren obwohl der Aufruf aus einem separaten
Thread stattfindet? Muss ich den Aufruf der C++ Methode anders gestalten? Ich habe auch schon versucht mit einem Delegate und BeginInvoke die Methode asynchron in
einem separaten Thread zu starten, aber dort erhalte ich den gleichen Effekt. Hat mir da jemand nen Ratschlag?
Mit freundlichen Grüssen
|
|
Th69
      

Beiträge: 4798
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 14.07.11 13:22
Hallo,
bist du dir sicher, daß es an dieser Methode liegt?
Ersetze mal testweise den Aufruf dieser Methode durch ein Thread.Sleep(10000). Blockiert dann weiterhin die GUI?
Ansonsten poste mal den Aufruf des modalen Dialogs sowie des Threads.
Und verwendest du das Locking-Object DllMutex noch irgendwo an anderer Stelle?
|
|
meisse 
      
Beiträge: 25
|
Verfasst: Do 14.07.11 14:20
Ich habe den Aufruf ersetzt durch ein Thread.Sleep:
C#-Quelltext 1: 2:
| Thread.Sleep(100000); |
Der modale Dialog funktioniert dadurch einwandfrei. Also muss es eigentlich an dieser Methode liegen.
Ja das Locking-Object wird noch bei allen anderen Methoden in der DLL auch verwendet. Also jedesmal wenn auf
eine C++ Methode zugegriffen wird, wird dieses Locking-Objekt verwendet. Zum testen habe ich dies mal kurz
auskommentiert, hatte aber auch keinen Erfolg damit.
Danach hatte ich gedacht, dass vielleicht der Callback von der C++ DLL zurück in die CSharp DLL ein Problem
sein könnte. Nach dem auskommentieren in der C++ DLL hatte ich aber auch damit kein Erfolg.
Danach habe ich einen Breakpoint genau dort in der C++ DLL gesetzt, wo die Daten fertig verarbeitet worden sind. Genau
ab dem Zeitpunkt wo die DLL fertig ist, ist auch das GUI wieder aktiv. Also irgendwie muss da was mit PInvoke los sein?
Mit freundlichen Grüssen
|
|
meisse 
      
Beiträge: 25
|
Verfasst: Do 14.07.11 14:48
Wenn ich das Sleep in die C++ Datei auslagere, dann warte ich auch genau die Zeit ab bis der GUI-Thread wieder aktiv ist:
C#-Quelltext 1: 2: 3: 4: 5:
| TPC_EXP TPC_ErrorCode TPC_CC TPC_GetRawDataStream(int deviceIx, int boardAddress, int inputNumber, int blockNumber, int measurementNumber, uint64_t dataStart, int dataLength, int bufferSize, TPC_DataStreamCallback callback) { Sleep(10000);
return TPC_ErrorCode::tpc_noError; |
(Der obige Code ist C++ und nicht CSharp)
Ich frage mich eigentlich, wieso dies passiert? Der ganze Aufruf geschieht ja extra auf einem separaten Thread... wieso sollte dies
dann den GUI-Thread blockieren??
|
|
meisse 
      
Beiträge: 25
|
Verfasst: Do 14.07.11 16:36
Ich habe nun ein komplettes eigenständiges Beispiel programmiert, welches PInvoke verwendet:
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:
| namespace PInvokeExample { public partial class Form1 : Form { System.Threading.Timer timer;
public Form1() { InitializeComponent(); TimerCallback cb = new TimerCallback(ProcessTimerEvent); timer = new System.Threading.Timer(cb, null, 2000, 5000); }
private void button1_Click(object sender, EventArgs e) { using (Status dialog = new Status()) { dialog.ShowDialog(); } }
public void ProcessTimerEvent(object obj) { Status.Addition("TimerThread", 5, 5); } }
public class Status : Form { ThreadStart execute; Thread thread; static object DllMutex = new object();
public Status() { this.Shown += new EventHandler(ShownDialog); }
public void ShownDialog(object sender, EventArgs e) { execute = new ThreadStart(Add); thread = new Thread(execute); thread.Start(); }
public void Add() { Addition("NormalThread", 5, 5); }
public static void Addition(string indentifier, int number0, int number1) { lock (DllMutex) { Console.WriteLine("Identifier: " + indentifier); int result = PInvokeExample.Addition(number0, number1); } } }
public class PInvokeExample { public const string dllName = "TestDLL.dll";
[DllImport(dllName)] public static extern int Addition(int number0, int number1); } } |
Der C++ Code sieht folgendermassen aus:
Quelltext 1: 2: 3: 4:
| TPC_EXP int TPC_CC Addition(int number0, int number1) { Sleep(10000); return number0+number1; } |
Es läuft ein Timer, welcher alle 5 sekunden die methode Addition in der C++ DLL aufruft.
Nebenbei hat die WinForm Applikation einen Button, mit welchem man automatisch auch die Addition
ausführt und ein zusätzliches modales Fenster öffnet. Man sieht jeweils auf der Konsole, dass
die Methoden je nach Aufrufreihenfolge (TimerThread, NormalThread) warten müssen, da wir ja ein
lock statement vor dem Methodenaufruf haben. Jedoch wird der Dialog, nach dem man auf den
Button geklickt hat, nicht blockiert. Irgendwie habe ich also in meiner Applikation einen anderen
Bock, dass der GUI Thread blockiert wird.
|
|
Th69
      

Beiträge: 4798
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Do 14.07.11 17:09
Hallo meisse,
da wirst du das wohl für dich alleine lösen müssen, denn aus der Ferne läßt sich da jetzt schwer etwas zu sagen (es hätte mich nur schwer verwundert, wenn es an dem DLL-Aufruf per se gelegen hätte).
Am besten, du reduzierst mal dein Projekt auf das nötigste (nach und nach einige Sachen auskommentieren), bis du den Fehler gefunden hast.
Laufen denn noch andere Threads oder Timer und greifst du evtl. von denen auf GUI-Elemente zu?
Ich hoffe mal, daß du nicht "Control.CheckForIllegalCrossThreadCalls = false" gesetzt hast (denn dies verschleiert nur falsche GUI-Zugriffe, löst aber nicht die Probleme).
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Do 14.07.11 18:55
Wenn du während des Blockierens per Debugger das Programm unterbrichst, solltest du im Stacktrace des GUI-Threads eigentlich ziemlich genau sehen können, wer hier die GUI von der Arbeit abhält  .
_________________ >λ=
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Do 14.07.11 19:16
Was macht den der C++Teil? Verwendest du dort COM oder irgendwelche Features die durch die MessagePump laufen? Oder passiert vielleicht noch irgendwas schlimmes im TPC_DataStreamCallback Callback?
|
|
meisse 
      
Beiträge: 25
|
Verfasst: Do 21.07.11 14:50
Mein Problem habe ich lokalisieren können. Diese locks waren an der Reaktion schuld. Es gab einen Aufruf aus einem GUI Thread auf die DLL welche in periodischen Abständen Requests gestartet hat. Diese Aufrufe haben so ziemlich alles lahm gelegt.
Mit freundlichen Grüssen
|
|
|