Internal data structures corrupted

Konzeptionelles, Technisches, Termine, Fragen zum Hersteller usw.

Moderator: Moderatoren

Antworten
Benz
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 440
Registriert: Mo, 30. Mai 2011 15:06
Danksagung erhalten: 1 Mal

Internal data structures corrupted

Beitrag von Benz »

Hi,

Im Anhang meine Fehlermeldung. Folgende Situation:

Code: Alles auswählen

         nAbfrageIntervall := ZEITEINS->ZEITIMP * 100

         oThread_import := Thread():new()
         oThread_import:start( {|| proc_verzeichnisabfrage(cSearchPath,cImportPath,oDlg_start,lApplicationReady) } )
         oThread_import:setInterval( nAbfrageIntervall )

         *************************************************************************
         * Artikelabfrage und Export der Artikel aus SelectLine in den Shop      *
         *************************************************************************
         nArtikelIntervall := ZEITEINS->ZEITEXP * 100 // *100: 100tel Sekunden, *60: Minuten, *1 Min

         oThread_export := Thread():new()
         oThread_export:start( {|| proc_artikel_export(cExportPath,oDlg_start,lApplicationReady)}  )
         oThread_export:setInterval( nArtikelIntervall )

Ich habe 2 Aufrufe, die getrennt voneinander ein Mal täglich und einmal pro Minute stattfinden. Dabei wird innerhalb dieser Proceduren ein COM-Objekt erzeugt. Soweit alles kein Problem funktioniert auch wunderbar. Bis sich die beiden Proceduren zufällig irgendwann überschneiden. Das Problem ist nämlich, dass das COM-Objekt nur einmal gleichzeitig erzeugt werden kann, das hat nämlich Lizenz Hintergründe.

Meine Idee: Ich erzeuge das COM-Objekt nur einmal und übergebe es als Parameter in

Code: Alles auswählen

proc_verzeichnisabfrage
und in

Code: Alles auswählen

proc_artikel_export
. Problem: Es erscheint die Fehlermeldung im Anhang, sobald die erste Methode des Objektes aufgerufen wird.

Zweiter Versuch: Ich erstelle das COM-Objekt als PUBLIC Variable. Resultat: Dieselbe Fehlermeldung.

Was kann ich tun?
Ich habe auch schon versucht das eine Intervall auszuschalten, solange das andere aktiv ist. Hat nicht wirklich funktioniert, aber das ist jetzt auch Nebensache. Gibt es eine Möglichkeit das COM-Objekt außerhalb der beiden Threads zu erzeugen und dann in die Threads zu übergeben?
Dateianhänge
fehler.png
fehler.png (18.09 KiB) 7849 mal betrachtet
UliTs
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2828
Registriert: Fr, 10. Feb 2006 9:51
Wohnort: Aachen
Hat sich bedankt: 259 Mal
Danksagung erhalten: 12 Mal
Kontaktdaten:

Re: Internal data structures corrupted

Beitrag von UliTs »

Mit Threads arbeiten und das vollständige abarbeiten der Methide ohne Unterbrechung erzwingen.
-------
Mitglied XuG Cologne
Mitglied XuG Osnabrück
georg
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2823
Registriert: Fr, 08. Feb 2008 21:29
Hat sich bedankt: 95 Mal
Danksagung erhalten: 13 Mal

Re: Internal data structures corrupted

Beitrag von georg »

Hallo, Benz -


die Fehlermeldung besagt, dass es eine Methode mit diesem Namen nicht gibt.

Da gibt es einen vorrangigen Grund: Tippfehler.

Alternativ kann es natürlich sein, dass ein Schritt beim Erstellen des AutomationObjekt nicht funktioniert. Wie sieht der entsprechende Befehl aus?
Liebe Grüsse aus der Eifel,

Georg S. Lorrig
Redakteur der Wiki des Deutschprachigen Xbase-Entwickler e.V.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Internal data structures corrupted

Beitrag von brandelh »

Vermutlich sind es nicht nur Lizenzgründe die das gleichzeitige Ausführen des COM Objektes verhindern.
Vermutlich ist dieses nicht nur nicht erlaubt, sondern wird eben nicht unterstützt ;-)

Schau mal bei den Beispielen nach coffee.prg
....\XPPW32\source\samples\basics\thread

Hier wird gezeigt dass Programmierer auf die Kaffeemaschine warten müssen, bis die gekocht hat, danach bekommt einer nach dem anderen Kaffee ... nicht gleichzeitig.

Im Prinzip schildert das dein Programm, 2 Arbeitsthreads wollen zum COM (Kaffee) ...

Man könnte das COM als eigenen Thread anlegen, aber ich denke es ist einfacher im Hauptprogramm eine FLAG Variable zu setzen, welche jeder Thread abfragt.
Falls die VAR NIL ist, kann der Thread versuchen seine Thread-ID dort zu speichern. Dann prüft er ob tatsächlich seine (der andere könnte schneller gewesen sein) eingetragen wurde ...
wenn ja, öffnet er den COM Kanal lokal ! und erledigt seinen Job ... danach wieder auf NIL setzen.
Sobald ein Thread die FLAG Var als belegt vorfindet, oder eine andere Thread-ID hinterlegt ist, muss er entweder warten oder wird beendet und beim nächsten Start der Job erledigt.
Gruß
Hubert
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Internal data structures corrupted

Beitrag von Tom »

Wenn Du das COM-Objekt aus Lizenzgründen nur einmal erzeugen kannst, kannst Du es auch nur einmal zur gleichen Zeit verwenden. Dabei dürfte keine Rolle spielen, ob das Objekt global erzeugt oder lokal erstellt und als Parameter weitergereicht wird. Du musst das entweder so synchronisieren, dass zu jeder Zeit nur eine Instanz des Objekts existiert, die exclusiv verwendet wird, oder die Lizenz erweitern.

Du hast nur einen Mietwagen, verleihst ihn aber zweimal. Der erste Kunde ist schon mit dem Wagen losgefahren und hat ihn zwar im Moment geparkt, aber nicht dort, wo der zweite Kunde das Auto erwartet, der ja denkt, er hätte soeben exklusiv dieses Auto gemietet. Und so weiter. Was auch immer Du mit dem mehrfach verwendeten Objekt machst - es killt irgendwas für die zweite Verwendung, und umgekehrt. Stell Dir vor, Du würdest ein Objekt für eine einfache Klasse erzeugen, die Kundendaten speichert. Der eine Thread schreibt Daten ins Objekt, der andere liest, glaubt aber, dass sich ganz andere Daten im Objekt befinden, und vice versa. Äußerst problematisch.
Herzlich,
Tom
Benz
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 440
Registriert: Mo, 30. Mai 2011 15:06
Danksagung erhalten: 1 Mal

Re: Internal data structures corrupted

Beitrag von Benz »

Erst einmal danke für die Antworten.

Tippfehler ist es nicht, das Ganze funktioniert ja, wenn ich das COM-Objekt innerhalb der Threads erzeuge.
Wenn Du das COM-Objekt aus Lizenzgründen nur einmal erzeugen kannst, kannst Du es auch nur einmal zur gleichen Zeit verwenden. Dabei dürfte keine Rolle spielen, ob das Objekt global erzeugt oder lokal erstellt und als Parameter weitergereicht wird. Du musst das entweder so synchronisieren, dass zu jeder Zeit nur eine Instanz des Objekts existiert, die exclusiv verwendet wird, oder die Lizenz erweitern.
Das heißt wohl neue Lizenz dazu kaufen.
Man könnte das COM als eigenen Thread anlegen, aber ich denke es ist einfacher im Hauptprogramm eine FLAG Variable zu setzen, welche jeder Thread abfragt.
Falls die VAR NIL ist, kann der Thread versuchen seine Thread-ID dort zu speichern. Dann prüft er ob tatsächlich seine (der andere könnte schneller gewesen sein) eingetragen wurde ...
wenn ja, öffnet er den COM Kanal lokal ! und erledigt seinen Job ... danach wieder auf NIL setzen.
Sobald ein Thread die FLAG Var als belegt vorfindet, oder eine andere Thread-ID hinterlegt ist, muss er entweder warten oder wird beendet und beim nächsten Start der Job erledigt.
Die Flag dann als PUBLIC Variable einfach anlegen oder?
Kann der Thread dann darauf zugreifen?
georg
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2823
Registriert: Fr, 08. Feb 2008 21:29
Hat sich bedankt: 95 Mal
Danksagung erhalten: 13 Mal

Re: Internal data structures corrupted

Beitrag von georg »

Hallo,


mal nicht so schnell mit den jungen Pferden ...

Mich zwicken derzeit einige Probleme mit Excel ...

Schaut Euch doch mal diesen XppFatal.log an:
C:\Entwicklungen\GListe>type XPPFATAL.LOG
FATAL ERROR LOG
Abort with Alt-C
SYS Thread-ID: 1136
Module: EVM
Error Codes: EH: 11 Sub: 0(0) OS: 0 XPP: 0
Call Stack of Thread 1 (1000):
@AUTOMATIONOBJECT@I@NOMETHOD(1232)
GENLISTFROMEXCEL(143)
MAIN(24)
Call Stack of GUI Thread (1136):
File: C:\Entwicklungen\myGListe\GZL.EXE
TimeStamp: 20180105 21:40
End of FATAL ERROR LOG.
Was passiert in GenListFromExcel an der Stelle?

Code: Alles auswählen

	nLine := 2
	WHILE oSheet:Cells(nLine, 1):value <> NIL
		cRange := "A" + LTrim(Str(nLine)) + ":C" + LTrim(Str(nLine))
		oRange := oSheet:Range(cRange)
	==>     oRange:select()
		aRange := oRange:Value
		AAdd(aList, AClone(aRange[1]))
		nLine ++
	END
Ich habe mal die Zeile 143 kenntlich gemacht. Im Debugger läuft das Programm ohne Fehler durch. Es wird eine Excel-Datei gelesen, und alle Werte aus den Spalten A bis C in ein dreidimensionales Array übertragen. (Ja, inzwischen weiss ich, dass man das performanter machen kann. Aber selbst nicht performanter Programmcode muss ordentlich abgearbeitet werden.)

Siehe hier: viewtopic.php?f=50&t=10265

Ich vermute also ein Problem seitens Microsoft. Wir hatten ja letzt wieder Updates ...
Liebe Grüsse aus der Eifel,

Georg S. Lorrig
Redakteur der Wiki des Deutschprachigen Xbase-Entwickler e.V.
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16502
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: Internal data structures corrupted

Beitrag von Martin Altmann »

Georg,
Deine XPPFATAL kannst Du getrost ignorieren - die kommt von Deinem Abbruch des Programmes mittels <ALT>-<C>

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
ramses
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2513
Registriert: Mi, 28. Jul 2010 17:16
Hat sich bedankt: 12 Mal
Danksagung erhalten: 77 Mal

Re: Internal data structures corrupted

Beitrag von ramses »

An einfachsten wäre doch:

Verlegte doch beide Abfragen in einen Thread und führe darin darin einmal im Tag nacheinander beide Abfragen durch.

Gruss Carlo
Valar Morghulis

Gruss Carlo
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Internal data structures corrupted

Beitrag von Tom »

Carlos Vorschlag ist gut. Ein Thread oder Timerevent, darin wird im Wechsel oder nacheinander geprüft, ob gerade eines der beiden Intervalle abgelaufen ist, dann wird das Objekt erzeugt, verwendet und wieder zerstört. Nachteil: Mehr Last in einem Thread, und beide Aktionen können dann nicht mehr gleichzeitig stattfinden. Das können sie aber sowieso nicht, wenn sich das Objekt nur einmal erzeugen lässt.
Wovon ich übrigens nicht überzeugt bin. Ich nutze einige Komponenten, aber die Einschränkung, dass man sie innerhalb einer Anwendung nur einmal verwenden darf, die kenne ich bislang nicht.
Herzlich,
Tom
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Internal data structures corrupted

Beitrag von AUGE_OHR »

ich sehe zunächst mal 2 x Threads die "nur" durch o:setInterval() "gesteuert" werden wobei der Zeit-Wert ( nAbfrageIntervall ) gleich ist.
ich sehen einen Import ... und einen Export aber der Sinn von 2 x Threads wird mir nicht ersichtlich :?:

ich "denke" man müsste erst einen vollständigen Import haben bevor man überhaupt einen Exoport starten dürfte ...
damit gilt der Tip von Ulli

Code: Alles auswählen

   oThread_import:start( ... )
   oThread_import:setInterval( nRandom )
   // warten bis der Thread gestartet ist
   SLEEP(10)
   // jetzt sollte o:active = .T. sein
   Do while oThread_import:active
#IFDEF UseInput
      nEvent := APPEVENT( @mp1, @mp2, @oXbp, 10 )
      DO CASE
         // timeout was tun ?
         CASE nEvent = xbe_None  
         // Keyboard ESC
         CASE nEvent = xbeP_Keyboard .AND. mp1 == xbeK_ESC
         ...
      OTHERWISE   
         oXbp:handleEvent( nEvent, mp1, mp2 )
      ENDIF
#ELSE
      SLEEP(10)
#ENDIF
   ENDDO
   // auf NIL setzten !
   oThread_import:setInterval(NIL)
---
ich habe 2 Aufrufe, die getrennt voneinander ein Mal täglich und einmal pro Minute stattfinden.
wie Carlo sagte :
bei einem Thread kannst du mittels o:startTime(nSeconds) festlegen wann der Thread gestartet werden soll.

angenommen es sollen wirklich 2 Thread laufen dann sollte :
a.) 1st Thread o:startTime(HMS2SEC("23:59:00"))
a.) der 2nd Thread mit + 30 Sec. (HMS2SEC("23:59:30")) starten
b.) nAbfrageIntervall sollte "dynamisch" ( RandomInt(55,65) ) sein. kann man zur Laufzeit verändern.

natürlich ist das immer noch nicht 100%, da muss du schon den Tip von Hubert mit SIGNAL() verwenden ... vergleichbar mit FLock(). man könnte auch eine Variabel, besser eine Function, als "Schalter" verwenden

Code: Alles auswählen

FUNCTION Running(lValue)
STATIC lRunning := .F.
   IF PCOUNT() > 0
      lRunning := lValue
   ENDIF
RETURN lRunning
---

die andere Frage : "was" für ein COM spricht du da an :?:

wie Tom denke ich das es nicht ein Lizenz Problem ist
um bei Toms Beipiel mit einem Auto zu bleiben :

Code: Alles auswählen

Import -> Vorwärtz fahren
Export -> Rückwärtz fahren
klar das es "so" nicht möglich ist wenn beide "gleichzeitig" agieren wollen [-X

also noch mal die Frage warum du 2 x Thread laufen lassen willst :?:
gruss by OHR
Jimmy
Antworten