Laden...

"Die angeforderte Ressource wird bereits verwendet"

Erstellt von MoaByter vor 3 Jahren Letzter Beitrag vor 3 Jahren 1.087 Views
M
MoaByter Themenstarter:in
68 Beiträge seit 2016
vor 3 Jahren
"Die angeforderte Ressource wird bereits verwendet"

hai und hallo,

ich bekam beim Debuggen die im Titel genannte Meldung und wüsste jetzt gerne, ob ich mit meiner Vermutung richtig liege.

Bei der zweiten Zeile (wbInfo = WebBrowser) kam die Meldung:

string txt1 = "Aktualisierung in: " + min + ":" + s_sec + i_sec + " min";
wbInfo.DocumentText = doc.Replace(m_rplc.Groups[1].Value, txt1);
return;

Auf den WebBrowser wird in gleicher Form von mehreren Stellen aus zugegriffen, allerdings sollte das vom Ablauf her nie gleichzeitig/überschneidend passieren - eigentlich auch beim Debuggen nicht. Wie frage ich ab, ob das WebBrowser.Dokument gerade beschrieben wird? Ich finde dazu leider nichts.

Der Fehler scheint auch nicht oft aufzutreten, er ließ sich jedenfalls nicht reproduzieren.
Danke für Hilfe/Kommentare.

...lypô

2.078 Beiträge seit 2012
vor 3 Jahren

Ohne mich wirklich mit diesem Control auszukennen:

Kommen die Zugriffe aus verschiedenen Threads? Es klingt ein wenig danach, da Du von gleichzeitigen Zugriffen (bzw. deren Ausbleiben) schreibst.
Es ist egal, ob die Zugriffe gleichzeitig passieren oder nicht, verschiedene Threads sind nicht erlaubt.
Ehrlich gesagt würde ich da aber eine bessere Fehlermeldung erwarten ...

Du kannst es ja mal in einem kleinen Test-Projekt nachstellen

M
MoaByter Themenstarter:in
68 Beiträge seit 2016
vor 3 Jahren

Danke für deine Antwort.

Ja, es sind mehrere Threads. Mittlerweile ist die Meldung aber wieder aufgetaucht: Während des Debuggens beim RechtsMausKlick auf den Browser während ein Timer die Zeitangabe alle Sekunden verändert. Ob das nun nur während des Debuggens auftritt, weiß ich nicht, im Normalbetrieb ist es noch nicht passiert.

Dennoch: Gibt es eine Möglichkeit, während des Schreibvorgangs im Timer einen threadfremden Zugriff zu erkennen? Alternativ müsste ich in der Vorlagedatei Javascript einsetzen, um die Veränderungen herbeizuführen, bin darin aber nicht sonderlich gut und habe es deswegen noch nicht probiert.

Mittlerweile konnte ich einen Screenshot der Meldung erstellen, der hängt an.

Und jetzt habe ich mal das HRESULT in die Suche eingegeben und wurde fündig:
https://stackoverflow.com/questions/2190390/how-to-fix-the-requested-resource-is-in-use-exception-from-hresult-0x800700a

Merkwürdig, dass die 'IsBusy'-Abfrage nicht funktionierte, war nämlich meine erste Idee. Also okay, wieder was dazu gelernt. damit dürfte sich das Thema erledigt haben. Danke für deine Hilfe!

Gehabt euch alle wohl, bleibt gesund - ...lypô

4.931 Beiträge seit 2008
vor 3 Jahren

Wie Palladin007 schon schrieb, darfst du aus anderen Threads nicht direkt auf UI-Controls zugreifen. Abhilfe s. [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke)
Trotzdem mußt du bei verschiedenen Threads immer passend synchronisieren (Stichwort: Race Condition)!

2.078 Beiträge seit 2012
vor 3 Jahren

Du kannst die ThreadId abrufen: Thread.CurrentThread.ManagedThreadId
Das in eine Watch packen, dann siehst Du immer, in welchem Thread Du gerade debuggst.
Es gibt noch andere Wege, das im Debugger sichtbar zu machen, doch das ist mMn. der einfachste Weg.

Wenn es mehrere Threads sind, musst Du die Aufrufe in den UI-Thread synchronisieren.
Wie das geht, hängt von dem UI-Framework ab, das Du nutzt, im Link von Th69 wird erklärt, wie.

Bei jedem UI-Framework sollte es aber eine SynchronizationContext-Implementierung geben, die das übernehmen kann, z.B. die Tasks in Verbindung mit async/await nutzen das.
Die statische SynchronizationContext.Current-Eigenschaft hat im UI-Thread dann die passende Implementierung, überall sonst steht da null drin - außer Du hast was Eigenes zugewiesen. Das Ding rufst Du dann im UI-Thread ab und gibst es für die Synchronisation an die jeweiligen Klassen weiter, die mit anderen Threads arbeiten.
Das hat den Charme, dass die Logik nichts vom verwendeten UI-Framework wissen muss, SynchronizationContext liegt nämlich in System.Threading.

Das ist natürlich kein Allheilmittel, aber nach dem, was ich bisher gelesen habe, eine mögliche Lösung.

M
MoaByter Themenstarter:in
68 Beiträge seit 2016
vor 3 Jahren

Ist ein Timer denn ein anderer Thread?

Ich starte in der 'Form1' einen Timer, um die Prozesse zu entkoppeln, und von dort aus beschreibe ich den Browser. Wenn der dann abgelaufen ist, wird ein BackgroundWorker in einer eigenen Klasse gestartet, der verschiedene Webzugriffe durchführt und am Schluss über Invoke in den WebBrowser eine Zeile einträgt. Klingt verrückt, dass ich nicht den ReportProgress verwende, nur wird mir der zu groß - zuviele Tests, wer meldet und was getan werden soll usw...

Das funktioniert ja auch ganz gut und sehr flott, nur kam eben diese merkwürdige Meldung. Aber nun ist's ja wohl gelöst. Dank auch dir für deine Hilfe.

Viele Grüße, alles Gute - ...lypô

M
MoaByter Themenstarter:in
68 Beiträge seit 2016
vor 3 Jahren

Uiuiui... Soweit bin ich mit meinen Kenntnissen noch nicht. Mit anderen Tasks hab' ich's mal versucht, war aber erfolglos, kommt also noch.

Ich notiere mal deinen Beitrag in meiner ToDo-Liste. Besonders den SynchonisationContext kenne ich nur namentlich. Das UI-Framework ist VisualStudio 2017, früher -express, jetzt wohl -common oder so ähnlich, die kostenlose Version also.

Ich habe jetzt erstmal genug Gedankenanstöße bekommen, die mich 'ne Weile beschäftigen werden. Da es so im Moment gut funktioniert, kann ich mich in Ruhe mit den anderen Dingen befassen.

Dir also auch recht herzlichen Dank, ich melde mich, wenn neue Fragen auftauchen.

Macht's gut, macht's besser - ...lypô

2.078 Beiträge seit 2012
vor 3 Jahren

Ist ein Timer denn ein anderer Thread?

Die Timer-Implementierungen in System.Timers und System.Threading arbeiten beide in eigenen Threads, ja. Die Implementierung von WinForms arbeite meine ich mit dem UI-Thread.

wird ein BackgroundWorker in einer eigenen Klasse gestartet

Der BackgroundWorker gehört in die Mottenkiste und wurde schon lange von den Tasks abgelöst.
Die Tasks machen das gleiche, nur dass es mit async/await in etwa wie normaler C#-Code aussieht, aber asynchron funktioniert, also weit übersichtlicher ist.

Mit anderen Tasks hab' ich's mal versucht, war aber erfolglos, kommt also noch.

Das ist keine Entschuldigung 😉
Nur deswegen auf alte Technik aufzubauen, ist Arbeit in die falsche Richtung.

Besonders den SynchonisationContext kenne ich nur namentlich

In den meisten Fällen braucht man den auch nicht.
Der wird erst dann spannend, wenn Du von irgendwo manuell zurück zum UI-Thread synchronisieren musst.

Der SynchronizationContext ist "nur" eine Abstraktion um den UI-Thread, normalerweise braucht man den nicht. Spannend wird er dann, wenn Du einen eigenständigen Thread (oder mehrere) unabhängig von der UI hast, aber zur UI synchronisieren musst.
Für alle "normalen" Operationen (z.B. Datenbankabfragen) reicht async/await aus.

Ich habe ihn deshalb erwähnt, weil die Nutzung des "direkten" Weges streng genommen eine Verletzung der Schichten-Architektur sein kann, der SynchronizationContext umgeht das Ganze.
Man muss nur darauf achten, dass man im UI-Thread ist, wenn man ihn abruft, danach reicht ein Post-Aufruf.

jetzt wohl -common oder so ähnlich

"Community"

4.931 Beiträge seit 2008
vor 3 Jahren

Das UI-Framework ist VisualStudio 2017, früher -express, jetzt wohl -common oder so ähnlich, die kostenlose Version also.

Mit UI-Framework ist "Windows Forms (WinForms)" oder WPF gemeint, du hast die Entwicklungsumgebung (IDE) genannt.
Aber aufgrund deiner verwendeten Klassen benutzt du wohl WinForms.

M
MoaByter Themenstarter:in
68 Beiträge seit 2016
vor 3 Jahren

Ja, ich meinte System.Windows.Forms -> SWF. Mit WPF habe ich mich noch nicht beschäftigt.

M
MoaByter Themenstarter:in
68 Beiträge seit 2016
vor 3 Jahren

Mit meinem Programm aktualisiere ich eine Webseite, d.h. ich erhalte Texte als PDF oder *.doc-Datei, das Programm formt diese passend um und lädt sie über ein dem Browser nachgebildetes Interface in eine Datenbank hoch. Das muss einwandfrei funktionieren - auch wenn's nur ein MiniJob ist, es ist 'n Job. Mit dem Backgroundworker tut's das, Aktualisierung auf Tasks dann, wenn ich mit den Task-Geschichten klar komme. Manches findet den Weg in mein Gehirn nicht so schnell. 😦 Und das ist 'ne Entschuldigung ... für mich ... vorerst.

Ich nutze den SWF-Timer. Bei den anderen muss ich mal schauen, was die bieten.

Bedankt, gehabe dich wohl - ...lypô

H
48 Beiträge seit 2020
vor 3 Jahren

es heisst winforms und nicht swf. swf ist die abkürzung für shockwave flash.

M
MoaByter Themenstarter:in
68 Beiträge seit 2016
vor 3 Jahren

using System.Windows.Forms;
using SWF = System.Windows.Forms;

...

SWF.Timer tm2 = new SWF.Timer { Interval = 1 };

Deswegen...

T
2.219 Beiträge seit 2008
vor 3 Jahren

Dir ist aber klar, dass du durch das erste using, direkt Timer als Klasse verwenden kannst ohne den unsinnigen SWF Namespace Ersatz oder?
Falls nicht, jetzt weißt du es.
Bitte nutzte solche Bezeichnungen/Namespace Alternativen nicht.
Außer dir kann nieman was mit den Bezeichnungen anfangen noch sind diese hilfreich.
Du solltest dir auch nochmal den Zweck von Namespaces anschauen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.