DbRelease(), DbRequest()

Alle Fragen um die Programmierung, die sich sonst nicht kategorisieren lassen. Von Makro bis Codeblock, von IF bis ENDIF

Moderator: Moderatoren

Benutzeravatar
Herbert
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 1991
Registriert: Do, 14. Aug 2008 0:22
Wohnort: Gmunden am Traunsee, Österreich
Danksagung erhalten: 3 Mal
Kontaktdaten:

DbRelease(), DbRequest()

Beitrag von Herbert »

Beim Stöbern bin ich auf diese beiden Commands gestossen.
Mir ist nicht ganz klar, was der Vorteil dieser beiden Befehle ist, als wenn man ganz klassisch in einem Thread die Datenbanken nochmals öffnet.

Wer weiss da was?
Grüsse Herbert
Immer in Bewegung...
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Moin Herbert,
dabei handelt es sich um den sogenannten Zerospace!
Man kann in einem Thread geöffnete Datenbanken ja nicht in einem anderen Thread ansprechen (also, ohne sie dort auch zu öffnen...).
Und darum gibt es den sogenannten Zerospace. Man kann also aus einem Thread die Datenbank in den Zerospace "verschieben" und in einem anderen Thread dann dort "abholen".

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.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15706
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 70 Mal
Danksagung erhalten: 34 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von brandelh »

Hallo Martin,

die Frage war doch aber warum man das machen sollte statt einfach neu zu öffnen ... das ist mir auch verschlossen geblieben ;-)
Schließlich sollen die Threads doch unabhängig bleiben :D
Gruß
Hubert
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Ach so - sorry, bin gerade erkältet und mein Geist ist vernebelt...
Gute Ausrede, wa?
Nun gut - dann erzähle ich mal wo und warum ich das in meinem Webserver nutze:
Wir haben bei unserem Onlinemelden eine Archivdatenbank, in der alle gemeldeten Hunde landen. Die Meldenden bekommen für jeden Hund eine eineindeutige ID, die sie beim erneuten Melden eingeben können, so dass sie nicht alles (nur einige wenige Angaben (zur Sicherheit)) erneut eingeben müssen.
Des weiteren wird durch die Aussteller für jeden der online gemeldeten Hunde vermerkt, ob die entsprechenden Nachweise (Championtitel und Arbeitsprüfungen) vorlagen - wenn ja, braucht bei einem erneuten Melden auch bei einer anderen Ausstellung kein Nachweis mehr eingeschickt werden.
Dieses Verwalten der Archivdatenbank passiert innerhalb einer eigenen Klasse (gekapselt) mit entsprechenden Schnittstellen nach außen (Methoden zum Suchen und zum Ändern eines hinterlegten Hundes sowie zum Hinterlegen der Titel und zum Bestimmen der Anzahl der Hunde im Archiv).
Und in dieser Klasse arbeite ich mit dem Zerospace. Beim Initialisieren der Klasse wird die Datenbank geöffnet und dann wird innerhalb der Methode immer mit dem Zerospace gearbeitet, da der Aufruf der o.g. Methoden ja immer aus einem anderen Thread erfolgt (Webserver!).

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.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

Hi,

ich klinke mich mal hier ein. Kann mir jemand mal ein Beispiel geben, wie man das macht? Ich verstehe nur Bahnhof. Wann muß ich was, wie in den Zerospace schieben und wann kann ich dann wie darauf zugreifen? Irgendwie klappt das bei mir nicht.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Moin,
damit einer das Dingen mittels DbRequest() sich krallen kann, muss der andere es erst mit DbRelease() wieder zurückgegeben haben!
Ich habe in meinem Fall also eine Klasse geschrieben, die den Zugriff auf meine zentrale Datei regelt (Daten suchen und Ergebnis zurückgeben, Daten suchen und aktualisieren - bzw. neu aufnehmen). Von dieser Klasse erzeuge ich beim Starten des Servers ein Objekt, welches ich allen Threads zugreifbar machen (globale Variable). Wann immer also in einem Thread auf diese zentrale Datei zugegriffen werden soll, geschieht das über die Klasse (bzw. das globale Objekt) und seine entsprechenden Methoden. In der jeweiligen Methode wird immer erst mittels DbRequest() die Datei "geholt" und wenn alles erledigt ist wieder mittels DbRelease() "freigegeben".

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.
manni1729
Cut&Paste-Entwickler
Cut&Paste-Entwickler
Beiträge: 30
Registriert: Mi, 04. Jun 2008 14:18
Wohnort: Nordhessen

Re: DbRelease(), DbRequest()

Beitrag von manni1729 »

Martin Altmann hat geschrieben: ...damit einer das Dingen mittels DbRequest() sich krallen kann, muss der andere es erst mit DbRelease() wieder zurückgegeben haben!
Hallo,
so wie Marin es gemacht hat, mache ich es auch.
Ich hbae einen TCP Server geschrieben, wo für jede Verbinndung ein neuer Thread aufgemacht wird. Alles was da drin passiert, wird über eine eigene Klasse in eine Logdatei(DBF) geschrieben. Die Logdatei wird zum schreiben aus den Zerospace geholt und danach wieder reingeschoben.

Gruß Manni
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

Das ist ja alles schön und gut, aber das ist nicht die Lösung meines Problems. Ich bekomme das programmtechnisch nicht hin. Wie sieht sowas aus?

Code: Alles auswählen

dbRelease(nArea)
Thread starten
dbrequest(cAlias)
...
oder wie? Es klappt nicht bei mir. Irgendwas mache ich falsch.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Manfred,
Du musst in Deinem Thread als erstes ein DbRequest() machen und wenn Du mit der Arbeit fertig bist, ein DbRelease(). Also erstens Andersherum, als von Dir skizziert und zweitens beides innerhalb des Threads, den Du mit Thread starten gestartet hast! Sonst kann Dein Thread nicht darauf zugreifen!
Und natürlich nur kurz aus dem Zerospace holen und schnell wieder zurück packen! Threads laufen ja parallel!

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.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

Hm,

die Reihenfolge kam mir schon spanisch vor. Release -> übertragen und Request abholen usw. Aber die Erklärung direkt hinter der Funktion schien mir so logisch. Ich hätte mal das Beispiel gaaanz genau lesen sollen.

Hm, das mit dem eben kurz holen und dann wieder zurückgeben, muß ich mal probieren.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

OK,

es klappt trotzdem nicht. Wie muß denn die jeweilige Funktion bestückt werden? Ich gebe im Debugger ein Dbrequest(alias) ein, aber es wird .F. zurückgeliefert.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Nun,
dann liegt nichts im Zerospace, was Du Dir an der Stelle holen könntest!
Du musst ganz am Anfang die DBF einmal öffnen und dann mittels DbRelease() in den Zerospace schieben. Dann kannst Du sie Dir in anderen Threads mittels DbRequest() holen.

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.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

Ich verstehe kein Wort.

Ich dachte ich kann "jede" DBF in den Thread holen, egal wann sie geöffnet wurde. Es wird doch der Selectbereich angegeben. Also muß ich doch vor Starten des Threads die/eine DBF in den Zerospace schieben.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

Sorry,

aber das paßt vorne und hinten nicht. Wir reden mal wieder aneinander vorbei.

Es wird doch vom aktuellen Workspace in den Zerospace übertragen und von dort in den neuen Workspace?

also doch Release-> Request und nicht andersherum. Aber trotzdem klappt es bei mir nicht.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15706
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 70 Mal
Danksagung erhalten: 34 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von brandelh »

Ich frage mich, warum Ihr nicht einfach die Datei in jedem Thread geshared öffnet und darin dann normal mit umgeht ?
Gruß
Hubert
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Im Zerospace kann nur eine DBF liegen!
Ein Thread kann nur auf eine DBF zugreifen, die in einem anderen Thread geöffnet wurde, wenn sie über den Zerospace ausgetauscht wird - also ein Thread schiebt sie mittels DbRelease() rein (das wird am Anfang Dein Hauptprogramm sein, das die DBF initial geöffnet hat) und ein anderer Thread kann sie sich dann dort mittels DbRequest() abholen, bearbeiten und mittels DbRelease() wieder zurückschieben, so dass weitere Threads drauf zugreifen können!

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.
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Hubert,
nicht alle Aktionen sind im shared Modus zulässig - oder?

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.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

@Hubert,

das hat einen ganz speziellen Grund bei mir. Ich versuche diesen aber gerade zu umgehen, mal sehen ob es klappt.

@Martin,

was spricht dagegen mal ein paar Zeilen zu schreiben, wie sowas auszusehen hat? Das erinnert mich ein wenig an den Nippel. Ist doch ganz einfach. Nur wie man es im Detail macht, verrät einem keiner.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

OK.

Code: Alles auswählen

CLASS HundeArchiv
  EXPORTED:
  	METHOD open
  	METHOD close
  	SYNC METHOD AnzDat
  	SYNC METHOD AnzDel
  	SYNC METHOD update
  	SYNC METHOD addtitles
  	SYNC METHOD search
  	SYNC METHOD delete
  HIDDEN:
  	CLASS VAR WorkA
  	CLASS VAR idnummer
ENDCLASS

METHOD HundeArchiv:open()
local aStructure
if .not. File( datenpfad + "\hundarch.dbf" )
	anlegen()
endif
use ( datenpfad + "\hundarch.dbf" ) NEW SHARED
::WorkA := Alias()
aStructure := DbStruct()         // Datei-Struktur einlesen
if ascan( aStructure, "GELOESCHT" ) == 0
	( ::WorkA )->( DbCloseArea() )
	AAdd( aStructure, { "GELOESCHT", "L", 1, 0 } )
	DbCreate( datenpfad + "\temphundarch.dbf", aStructure ) // Temporäre Datei mit neuer Struktur erzeugen und öffnen
	use ( datenpfad + "\temphundarch.dbf" ) NEW ALIAS TEMPHAR
	APPEND FROM ( datenpfad + "\hundarch.dbf" )                       // Datensätze von alter Datei übernehmen
	CLOSE TEMPHAR
	ERASE ( datenpfad + "\hundarch.dbf" )       // Quell-Datei löschen
	RENAME ( datenpfad + "\temphundarch.dbf" ) TO ( datenpfad + "\hundarch.dbf" )    // Temporäre Datei umbenennen
	use ( datenpfad + "\hundarch.dbf" ) NEW SHARED
	::WorkA := Alias()
endif
OrdCreate( datenpfad + "\idnr.ntx", , "IDNR" )
( ::WorkA )->( DbGoTop() )
( ::WorkA )->( DbGoBottom() )
::idnummer := iif( empty( ( ::WorkA )->IDNR ), 0, code2int( right( ( ::WorkA )->IDNR, 4 ) ) ) + 1
( ::WorkA )->( DbGoTop() )
DbRelease( ::WorkA )
Return self

METHOD HundeArchiv:addtitles( datname )
local bSaveError, oError, i, lRLock, links, rechts, gefunden, mitte, abbruch, nAnz
bSaveError := ErrorBlock()
ErrorBlock( {|e| Break(e)} )
BEGIN SEQUENCE
	if file( datname )
		DbRequest( ::WorkA, .t. )
		use ( datname ) NEW ALIAS Titleimp
		Titleimp->( DbGoTop() )
		nAnz := 0
		do while .not. Titleimp->( Eof() )
			gefunden := .f.
			abbruch := .f.
			links   := 1
			rechts  := ( ::WorkA )->( lastrec() )
			( ::WorkA )->( DbGoto( links ) )
			if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( Titleimp->IDNR ) )
				gefunden := .t.
				abbruch := .t.
			else
				( ::WorkA )->( DbGoto( rechts ) )
				if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( Titleimp->IDNR ) )
					gefunden := .t.
					abbruch := .t.
				else
					mitte := links + int( ( rechts - links ) / 2 )
				endif
			endif
			do while .not. abbruch
				( ::WorkA )->( DbGoto( mitte ) )
				if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( Titleimp->IDNR ) )
					abbruch := .t.
					gefunden := .t.
				endif
				if .not. abbruch
					if alltrim( upper( ( ::WorkA )->IDNR ) ) > alltrim( upper( Titleimp->IDNR ) )
						rechts := ( ::WorkA )->( recno() )
					elseif alltrim( upper( ( ::WorkA )->IDNR ) ) < alltrim( upper( Titleimp->IDNR ) )
						links := ( ::WorkA )->( recno() )
					endif
					mitte := links + int( ( rechts - links ) / 2 )
					if ( ( links >= rechts ) .or. ( links == mitte ) .or. ( rechts == mitte ) )
						abbruch := .t.
						gefunden := .f.
					endif
				endif
			enddo
			if gefunden
				i := 0
				DO WHILE ( .NOT. ( lRLock := ( ::WorkA )->( DbRLock( ( ::WorkA )->( recno() ) ) ) ) ) .and. ( i < 3 )
					Sleep( 50 )
					i++
				ENDDO
				IF lRLock
					if Titleimp->ETITBEST .and. empty( ( ::WorkA )->EHRENBEST )
						( ::WorkA )->EHRENBEST := Titleimp->USERNAME
						nAnz++
					endif
					if ( Titleimp->STITBEST .or. Titleimp->ETITBEST ) .and. empty( ( ::WorkA )->SIEGBEST )
						( ::WorkA )->SIEGBEST := Titleimp->USERNAME
						nAnz++
					endif
					if Titleimp->GTITBEST .and. empty( ( ::WorkA )->GEBBEST )
						( ::WorkA )->GEBBEST := Titleimp->USERNAME
						nAnz++
					endif
					( ::WorkA )->( DbCommit() )
					( ::WorkA )->( DbRUnlock( ( ::WorkA )->( recno() ) ) )
				endif
			endif
			Titleimp->( DbSkip() )
		enddo
		DbRelease( ::WorkA )
		SaveToFile( ConvToAnsiCP( "      " + alltrim( str( nAnz ) ) + " Titel von " + alltrim( str( Titleimp->( lastrec() ) ) ) + " Datensätzen wurden importiert!" ), SOAP_LOG )
		Close Titleimp
	else
		SaveToFile( ConvToAnsiCP( "      Die Titeldatei ist nicht vorhanden -> kein Import!!!" ), SOAP_LOG )
	endif
RECOVER USING oError
	ErrorBlock( bSaveError )
	SaveToFile( "Fehler im Server!", SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:args         :" + Var2Char( oError:args ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:canDefault   :" + Var2Char( oError:canDefault ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:canRetry     :" + Var2Char( oError:canRetry ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:canSubstitute:" + Var2Char( oError:canSubstitute ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:cargo        :" + Var2Char( oError:cargo ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:description  :" + Var2Char( oError:description ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:filename     :" + Var2Char( oError:filename ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:genCode      :" + Var2Char( oError:genCode ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:operation    :" + Var2Char( oError:operation ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:osCode       :" + Var2Char( oError:osCode ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:severity     :" + Var2Char( oError:severity ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:subCode      :" + Var2Char( oError:subCode ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:subSystem    :" + Var2Char( oError:subSystem ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:thread       :" + Var2Char( oError:thread ), SERVER_ERR_LOG_FILE )
	SaveToFile( "oError:tries        :" + Var2Char( oError:tries ), SERVER_ERR_LOG_FILE )
END SEQUENCE
return self

METHOD HundeArchiv:update( felder, idnum )
local i, lRLock, links, rechts, gefunden, mitte, abbruch
	DbRequest( ::WorkA, .t. )
	if empty( idnum )
		idnum := "A" + right( "0000" + int2code( ::idnummer ), 4 )
		::idnummer++
	endif
	gefunden := .f.
	abbruch := .f.
	links   := 1
	rechts  := ( ::WorkA )->( lastrec() )
	( ::WorkA )->( DbGoto( links ) )
	if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
		gefunden := .t.
		abbruch := .t.
	else
		( ::WorkA )->( DbGoto( rechts ) )
		if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
			gefunden := .t.
			abbruch := .t.
		else
			mitte := links + int( ( rechts - links ) / 2 )
		endif
	endif
	do while .not. abbruch
		( ::WorkA )->( DbGoto( mitte ) )
		if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
			abbruch := .t.
			gefunden := .t.
		endif
		if .not. abbruch
			if alltrim( upper( ( ::WorkA )->IDNR ) ) > alltrim( upper( idnum ) )
				rechts := ( ::WorkA )->( recno() )
			elseif alltrim( upper( ( ::WorkA )->IDNR ) ) < alltrim( upper( idnum ) )
				links := ( ::WorkA )->( recno() )
			endif
			mitte := links + int( ( rechts - links ) / 2 )
			if ( ( links >= rechts ) .or. ( links == mitte ) .or. ( rechts == mitte ) )
				abbruch := .t.
				gefunden := .f.
			endif
		endif
	enddo
	if .not. gefunden
		( ::WorkA )->( DbAppend( 1 ) )
		( ::WorkA )->IDNR := idnum
		lRLock := .t.
	else
		i := 0
		DO WHILE ( .NOT. ( lRLock := ( ::WorkA )->( DbRLock( ( ::WorkA )->( recno() ) ) ) ) ) .and. ( i < 3 )
			Sleep( 50 )
			i++
		ENDDO
	endif
	IF lRLock
		( ::WorkA )->ZUCHTBUCHN := felder[ 1 ]
		( ::WorkA )->HUNDENAMEN := felder[ 2 ]
		( ::WorkA )->GEBDATUM := felder[ 3 ]
		( ::WorkA )->GESCHLECHT := felder[ 4 ]
		( ::WorkA )->VATER := felder[ 5 ]
		( ::WorkA )->MUTTER := felder[ 6 ]
		( ::WorkA )->ZUECHTER := felder[ 7 ]
		( ::WorkA )->PLZ := felder[ 8 ]
		( ::WorkA )->ORT := felder[ 9 ]
		( ::WorkA )->NATIONAL := felder[ 10 ]
		( ::WorkA )->STRASSE := felder[ 11 ]
		( ::WorkA )->TELEFON := felder[ 12 ]
		( ::WorkA )->KUPIERT := felder[ 13 ]
		( ::WorkA )->CHIPNR := felder[ 14 ]
		( ::WorkA )->BESITZERVO := felder[ 15 ]
		( ::WorkA )->BESITZERNA := felder[ 16 ]
		( ::WorkA )->EMAIL := felder[ 17 ]
		( ::WorkA )->NATIONAL2 := felder[ 18 ]
		( ::WorkA )->GEBRAUCH1 := felder[ 19 ]
		( ::WorkA )->GEBRAUCH2 := felder[ 20 ]
		( ::WorkA )->SIEGER := felder[ 21 ]
		( ::WorkA )->( DbCommit() )
		( ::WorkA )->( DbRUnlock( ( ::WorkA )->( recno() ) ) )
	endif
	DbRelease( ::WorkA )
return self

METHOD HundeArchiv:AnzDat()
local nAnz
DbRequest( ::WorkA, .t. )
nAnz := iif( .not. empty( ::WorkA ), ( ::WorkA )->( reccount() ), 0 )
DbRelease( ::WorkA )
return nAnz

METHOD HundeArchiv:AnzDel()
local nAnz
nAnz := 0
DbRequest( ::WorkA, .t. )
if .not. empty( ::WorkA )
	( ::WorkA )->( DbGoTop() )
	( ::WorkA )->( DbEval( {|| nAnz++ }, {|| GELOESCHT } ) )
endif
DbRelease( ::WorkA )
return nAnz

METHOD HundeArchiv:search( felder, idnum )
local gefunden, cDatum, text, links, rechts, abbruch, mitte
	DbRequest( ::WorkA, .t. )
	gefunden := .f.
	if .not. empty( idnum )

		abbruch := .f.
		links   := 1
		rechts  := ( ::WorkA )->( lastrec() )
		( ::WorkA )->( DbGoto( links ) )
		if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
			gefunden := .not. ( ::WorkA )->GELOESCHT
			abbruch := .t.
		else
			( ::WorkA )->( DbGoto( rechts ) )
			if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
				gefunden := .not. ( ::WorkA )->GELOESCHT
				abbruch := .t.
			else
				mitte := links + int( ( rechts - links ) / 2 )
			endif
		endif
		do while .not. abbruch
			( ::WorkA )->( DbGoto( mitte ) )
			if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
				gefunden := .not. ( ::WorkA )->GELOESCHT
				abbruch := .t.
			endif
			if .not. abbruch
				if alltrim( upper( ( ::WorkA )->IDNR ) ) > alltrim( upper( idnum ) )
					rechts := ( ::WorkA )->( recno() )
				elseif alltrim( upper( ( ::WorkA )->IDNR ) ) < alltrim( upper( idnum ) )
					links := ( ::WorkA )->( recno() )
				endif
				mitte := links + int( ( rechts - links ) / 2 )
				if ( ( links >= rechts ) .or. ( links == mitte ) .or. ( rechts == mitte ) )
					abbruch := .t.
					gefunden := .f.
				endif
			endif
		enddo
		if gefunden
			text := dtos( ctod( felder[ 1 ] ) )
			cDatum := right( text, 2 ) + substr( text, 5, 2 ) + left( text, 4 )
			if ( cDatum == ( ::WorkA )->GEBDATUM ) .and. ( felder[ 2 ] == ( ::WorkA )->GESCHLECHT )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->ZUCHTBUCHN ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->HUNDENAMEN ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->VATER ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->MUTTER ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->ZUECHTER ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->PLZ ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->ORT ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->NATIONAL ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->STRASSE ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->TELEFON ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->KUPIERT ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->CHIPNR ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->BESITZERVO ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->BESITZERNA ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->EMAIL ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->NATIONAL2 ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->GEBRAUCH1 ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->GEBRAUCH2 ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->SIEGER ) ) )
				aAdd( felder, .not. empty( ( ::WorkA )->GEBBEST ) )
				aAdd( felder, .not. empty( ( ::WorkA )->SIEGBEST ) )
				aAdd( felder, .not. empty( ( ::WorkA )->EHRENBEST ) )
			else
				gefunden := .f.
			endif
		endif
	endif
	DbRelease( ::WorkA )
return gefunden

METHOD HundeArchiv:delete( felder, idnum )
local i, lRLock, gefunden, cDatum, text, links, rechts, abbruch, mitte
	DbRequest( ::WorkA, .t. )
	gefunden := .f.
	if .not. empty( idnum )

		abbruch := .f.
		links   := 1
		rechts  := ( ::WorkA )->( lastrec() )
		( ::WorkA )->( DbGoto( links ) )
		if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
			gefunden := .not. ( ::WorkA )->GELOESCHT
			abbruch := .t.
		else
			( ::WorkA )->( DbGoto( rechts ) )
			if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
				gefunden := .not. ( ::WorkA )->GELOESCHT
				abbruch := .t.
			else
				mitte := links + int( ( rechts - links ) / 2 )
			endif
		endif
		do while .not. abbruch
			( ::WorkA )->( DbGoto( mitte ) )
			if alltrim( upper( ( ::WorkA )->IDNR ) ) == alltrim( upper( idnum ) )
				gefunden := .not. ( ::WorkA )->GELOESCHT
				abbruch := .t.
			endif
			if .not. abbruch
				if alltrim( upper( ( ::WorkA )->IDNR ) ) > alltrim( upper( idnum ) )
					rechts := ( ::WorkA )->( recno() )
				elseif alltrim( upper( ( ::WorkA )->IDNR ) ) < alltrim( upper( idnum ) )
					links := ( ::WorkA )->( recno() )
				endif
				mitte := links + int( ( rechts - links ) / 2 )
				if ( ( links >= rechts ) .or. ( links == mitte ) .or. ( rechts == mitte ) )
					abbruch := .t.
					gefunden := .f.
				endif
			endif
		enddo
		if gefunden
			text := dtos( ctod( felder[ 1 ] ) )
			cDatum := right( text, 2 ) + substr( text, 5, 2 ) + left( text, 4 )
			if ( cDatum == ( ::WorkA )->GEBDATUM ) .and. ( felder[ 2 ] == ( ::WorkA )->GESCHLECHT )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->ZUCHTBUCHN ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->HUNDENAMEN ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->VATER ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->MUTTER ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->ZUECHTER ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->PLZ ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->ORT ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->NATIONAL ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->STRASSE ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->TELEFON ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->KUPIERT ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->CHIPNR ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->BESITZERVO ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->BESITZERNA ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->EMAIL ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->NATIONAL2 ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->GEBRAUCH1 ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->GEBRAUCH2 ) ) )
				aAdd( felder, ConvToANSICp( alltrim( ( ::WorkA )->SIEGER ) ) )
				aAdd( felder, .not. empty( ( ::WorkA )->GEBBEST ) )
				aAdd( felder, .not. empty( ( ::WorkA )->SIEGBEST ) )
				aAdd( felder, .not. empty( ( ::WorkA )->EHRENBEST ) )
				i := 0
				DO WHILE ( .NOT. ( lRLock := ( ::WorkA )->( DbRLock( ( ::WorkA )->( recno() ) ) ) ) ) .and. ( i < 3 )
					Sleep( 50 )
					i++
				ENDDO
				IF lRLock
					( ::WorkA )->GELOESCHT := .t.
					( ::WorkA )->( DbCommit() )
					( ::WorkA )->( DbRUnlock( ( ::WorkA )->( recno() ) ) )
				else
					gefunden := .f.
				endif
			else
				gefunden := .f.
			endif
		endif
	endif
	DbRelease( ::WorkA )
return gefunden

METHOD HundeArchiv:close()
	DbRequest( ::WorkA, .t. )
	( ::WorkA )->( OrdListClear() )
	( ::WorkA )->( DbCloseArea() )
return self
....
....
	MEMVAR->HauptArchiv := HundeArchiv():new()
	MEMVAR->HauptArchiv:open()
....
....
	if MEMVAR->HauptArchiv:delete( @felder, alltrim( upper( alleFelder[ I_SIDNR ] ) ) )
....
....
	if MEMVAR->HauptArchiv:search( @felder, alltrim( upper( alleFelder[ I_SIDNR ] ) ) )
		alleFelder[ I_GEBDATUM ] := felder[ 1 ]
		alleFelder[ I_GESCHLECHT ] := felder[ 2 ]
		alleFelder[ I_CODEN ] := felder[ 3 ]
		alleFelder[ I_HUNDEKLASS ] := felder[ 4 ]
		if l2s
			alleFelder[ I_HUNDEKLAS2 ] := felder[ 5 ]
		endif
		alleFelder[ I_ZUCHTBUCHN ] := felder[ 6 ]
....
....
		MEMVAR->HauptArchiv:update( felder, @idnum )
		if empty( Melde->IDNR )
			Melde->IDNR := idnum
		endif
....
....
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.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15706
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 70 Mal
Danksagung erhalten: 34 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von brandelh »

Martin Altmann hat geschrieben:Hubert,
nicht alle Aktionen sind im shared Modus zulässig - oder?
Viele Grüße,
Martin
Du PACKst Dateien auf deinem Web-Server ?

Seit Jahrzehnten programmiere ich Anwendungen im LAN für viele Anwender (auch wenn die tatsächliche gleichzeitige Verwendung eher bei 10 lag).
PACK brauche ich nicht, ich lösche über den Index und verwende gelöschte Datensätze erneut.
Laut DOKU muss man die Cache Verweilzeit kürzen und neuerdings sicher auch die Server entsprechend preparieren ... außer bei einem CGI Webserver, weil der ja alles nur lokal macht.

Egal wie, muss man alles vermeiden was einen exclusiven Zugriff braucht, schließlich weiß man nie wann der nächste Thread auf die Datei zugreifen will,
schließlich macht man doch Threads um mehrere Anfragen gleichzeitig abzuarbeiten.

Oder ist das eine Datei die seltene Steueraufgaben für alle Threads regeln soll ?
Gruß
Hubert
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Moin Hubert,
nein - mache ich nicht.
Diese Datei enthält aktuell 43.581 Datensätze (Hunde) und es darf nie eine ID zum eineindeutigen Identifizieren doppelt vergeben werden!
Also nix mit shared und mehrfacher Zugriff.

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.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

Hi martin,

toll, jetzt hast Du mir 1000 Nippel mit 1000 Laschen rübergeschmissen. Daran sehe ICH aber nicht, wie man EINEN Nippel durch EINE Lasche zieht. :roll:
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16555
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 115 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von Martin Altmann »

Klar siehst Du das.
Nimm die Klasse für sich - am Ende folgen die Aufrufe.
Es fängt an mit dem Instanziieren der Klasse und dem Öffnen der Datenbank:

Code: Alles auswählen

   MEMVAR->HauptArchiv := HundeArchiv():new()
   MEMVAR->HauptArchiv:open()
Dies passiert nur an einer Stelle und nur einmalig. Die anderen Aufrufe können danach beliebig oft erfolgen. In den dort aufgerufenen Methoden siehst Du dann immer, wie mittels DbRelease() und DbRequest() gearbeitet wird.

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.
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21224
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: DbRelease(), DbRequest()

Beitrag von Manfred »

OK,

suche ich den Fehler erstmal wieder bei mir.

Code: Alles auswählen

Procedure wasweißich(oThread)    // das ist der Thread, der gestartet wird
              memvar oId

              workspacelist()  // nix offen
              DbRequest(oId:cAlias)
              workspacelist() // nix offen
              return
ist das erstmal so korrekt? Oder falsch gedacht, oder fehlt da noch was, oder was weiß ich?
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15706
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 70 Mal
Danksagung erhalten: 34 Mal
Kontaktdaten:

Re: DbRelease(), DbRequest()

Beitrag von brandelh »

Martin Altmann hat geschrieben:Moin Hubert,
nein - mache ich nicht.
Diese Datei enthält aktuell 43.581 Datensätze (Hunde) und es darf nie eine ID zum eineindeutigen Identifizieren doppelt vergeben werden!
Also nix mit shared und mehrfacher Zugriff.
Viele Grüße,
Martin
das ist ein Grund und man kann es so machen ... aber es geht auch anders. Insbesonder im SHARED Zugriff :!:

Man braucht nur FLOCK() verwenden um die neue Nummer zu bilden, mit meiner alten Routine mit RLOCK() gab es theoretisch das Problem dass doppelte möglich waren.
Im LAN bei 10 Anwendern trat dies nie auf, aber im WEB mit vielen ist die Gefahr größer.
Vor kurzem habe ich dazu Tests auf meinem NAS und auch auf Windowsserver durchgeführt und veröffentlicht, dort findet man auch die Funktionen.
Gruß
Hubert
Antworten