Dies kann eine dumme Frage sein und wenn dies bereits an anderer Stelle beantwortet wurde, dann würde ich es wirklich schätzen, wenn jemand mich darauf hinweisen könnte, da meine Suche nicht aufgetaucht ist etwas Definitives.Thread.Join im UI-Thread blockiert auch Kind-Thread
Auf den Punkt gebracht, mein Problem ist, dass, wenn ich childThread.Join() im UI-Thread auf einem untergeordneten Thread zu tun, die die childThread zu stoppen markiert wurde scheint sowie dem Haupt-Thread zu blockieren, so dass alles hängt einfach.
Dass die Benutzeroberfläche aufgrund der Verwendung von Join blockiert wird, ist im Moment kein Problem, da das childThread in weniger als einer Sekunde enden sollte, nachdem es sowieso beendet wurde.
Dies passiert, während ich darauf warte, dass ein Thread, der einen wiederholten Prozess ausführt, beendet wird, bevor ich eine andere Methode ausführen kann, die einige Informationen zurückgibt, aber nicht gleichzeitig mit dem anderen Prozess ausgeführt werden kann.
Meine Winforms-Anwendung integriert sich mit einem Stück USB-Hardware, indem Sie die C-API für die Hardware pinvokieren.
Die Hardware-API verfügt über eine Methode, die einen Prozess startet, der unbegrenzt und wiederholt ausgeführt wird und schnell mit neuen Informationen zurückruft, die ich dann an die Benutzeroberfläche weiterleiten muss.
Diese Operation kann durch einen anderen Aufruf der Hardware-API abgebrochen werden, die ein Flag setzt, das die Hardware sehen kann, damit sie es beenden kann.
Ich habe diese C-API mit meinem eigenen C# -Code umschlossen, und innerhalb des Wrappers musste ich den Aufruf des Startprozesses in einem anderen Thread aufheben, damit die Aktivität die Benutzeroberfläche nicht blockiert.
Hier sind die bearbeiteten Highlights von grob, was ich mache.
public class DeviceWrapper
{
Thread childThread = null;
void DeviceWrapper
{
//Set the callback to be used by the StartGettingInformation() process
PInvokeMethods.SetGetInformationCallback(InformationAcquiredCallback);
}
public void StartProcess()
{
childThread = new Thread(new ThreadStart(GetInformationProcess))
childThread.Start();
}
void GetInformationProcess()
{
PInvokeMethods.StartGettingInformation();
}
//This callback occurs inside the childThread
void InformationAcquiredCallback(Status status, IntPtr information)
{
//This callback is triggered when anything happens in the
//StartGettingInformation() method, such as when the information
//is ready to be retrieved, or when the process has been cancelled.
if(status == Status.InformationAcquired)
{
FireUpdateUIEvent();
}
//If the cancel flag has been set to true this will be hit.
else if(status == Status.Cancelled)
{
//Reset the cancel flag so the next operation works ok
PInvokeMethods.SetCancelFlag(false);
childThread.Abort();
}
}
//This method runs once, and can't run at the same time as GetInformationProcess
public string GetSpecificInformation()
{
//This triggers InformationAcquiredCallback with a status of Cancelled
StopProcess();
if(childThread.IsAlive)
{
childThread.Join();
}
return PInvokeMethods.GetSpecificInformation();
}
public void StopProcess()
{
PInvokeMethods.SetCancelFlag(true);
}
}
diesen Code verwenden, wenn ich rufe childThread.Join() die gesamte Anwendung zum Stillstand kommt (was ich für die Benutzeroberfläche erwarten würde und das ist in Ordnung) und der childThread auch, weil der Rückruf wird nie zu stoppen scheinen wieder getroffen.
Allerdings, wenn ich den folgenden Code statt:
public string GetSpecificInformation()
{
//This triggers InformationAcquiredCallback with a status of Cancelled
StopProcess();
string s = "";
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
if(childThread.IsAlive)
{
childThread.Join();
}
s = PInvokeMethods.GetSpecificInformation();
}));
return s;
}
Dann wird alles getroffen als erwartet und childThread tut beenden und alles ist gut, außer offensichtlich meine Zeichenfolge vor dem WaitCallback Feuer leer zurückgegeben werden und ordnen es.
Also, muss ich nur saugen und ändern Sie die Klasse, so dass ich die QueueUserWorkItem und WaitCallback und feuern ein Ereignis, um mit meiner String-Rückgabe umzugehen?
Gibt es etwas Dummes, das ich in meinem ersten Ansatz mache, was dazu führt, dass der ChildThread ebenfalls blockiert?
Oder gibt es eine andere Taktik oder Klasse, die ich verwenden sollte, wenn man bedenkt, dass es .NET 3.5 ist?
Ich habe die letzten 30 Jahre damit verbracht, zu versuchen, Delphi-Entwickler mit TThread.WaitFor() und anderen solchen Hard-Lock-Synchronisationsmechanismen zu stoppen, die Deadlocks generieren. Gerade wenn ich denke, dass ich irgendwo hinkomme, entdecken Java und C# Entwickler join(). Ein nie endender Albtraum. –
Glauben Sie mir, ich würde nichts davon berühren, wenn ich nicht verzweifelt und aus meiner Tiefe wäre;) Was würden Sie stattdessen empfehlen? – Nanhydrin
Wenn Sie Eric und andere Re hören. Aufrufen, BeginInvoke usw., Sie werden nicht weit falsch liegen. Warte nicht in Event-Handlern - handle auf Signale, die zurückgegeben werden, indem Delegierte auf den Haupt-Thread geschossen werden, wenn die anderen Threads etwas zu sagen haben. –