Thread und dbf [Erledigt]

Konzeptionelles, Technisches, Termine, Fragen zum Hersteller usw.

Moderator: Moderatoren

Antworten
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14658
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Thread und dbf [Erledigt]

Beitrag von Jan »

Kann jemand mir erklären, wie ich in einem anderen als dem aktuellen Thread alle dbf schließen, das Verzeichnis wechseln, und andere dbf neu öffnen kann?

Jan
Zuletzt geändert von Jan am Di, 08. Sep 2009 6:53, insgesamt 1-mal geändert.
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Re: Thread und dbf

Beitrag von AUGE_OHR »

Jan hat geschrieben:Kann jemand mir erklären, wie ich in einem anderen als dem aktuellen Thread alle dbf schließen, das Verzeichnis wechseln, und andere dbf neu öffnen kann?
theoretisch ...

jeder Thread hätte ja seine WorkSpaceList()
eine WorkSpaceList() könnte man in den DB_ZEROSPACE legen
mit DbRequest() könnte man den Aliasnamen aus dem Zerospace in den aktuellen Workspace übertragen
mit DbRelease() könnte man den Aliasnamen aus dem aktuellen Workspace in den Zerospace übertragen
mit DbJob() könnte man den Workarea-Codeblock abfragen

und wenn man die ganzen "könnte" zu einem Puzzle zusammen bekommt, dann "könnte" es theoretisch funktionieren ;)

ich habe sowass noch nicht "gebaut" und wüsste gerne für welchen Zweck du das vorhast ? anderen "Mandanten" ?
Jan hat geschrieben:Verzeichnis wechseln
würde ich "so" nicht tun. ich habe immer einen Kompletten Path zur Dbf / Index.
Wenn ich den Mandanten Wechsel, dann den Path zur DBF, aber nicht das Applications Verzeichniss das könnte "ungünstig" sein.


was nun das "kommunizieren" von Threads angeht : ich verwenden USER_DEF Events und den 4th Parameter nTimeout in AppEvent.

wenn ich "einem" Thread einen Event senden will : PostAppEvent(myDEF,mp1,mp2,oThreadNo)

bei xbe_None = "Timeout" fragt jeder Thread den "Main-Stack" ab, welches ein n-Dim Array ist,
ob für "ihn" eine Msg (=Event) vorhanden ist.

der "Main Stack" ist ein separates PRG mit 2 "Fieldwide" STATIC für das n-Dim Array.
per "#define xtranslate =>" übersetze ich die Element des Arrays (leicht erweiterbar)
und zur identifizierung der n-Dim nutze ich :getHWND() (oder ThreadID aus ThreadInfo() )

Durch Functionen greife ich nun "von aussen" auf das n-Dim Array zu, wobei ohne Parameter = "get" und mit Parameter = "set"

Code: Alles auswählen

// "m"+ DBF FieldName
#xtranslate mARTIST      => Stack\[SP,1]
#xtranslate mW9VIDEO    => Stack\[SP,2]
...
// sonstige
#xtranslate aEditControls => Stack\[SP,17]
#xtranslate hWndEdit      => Stack\[SP,18]

STATIC Stack         := {}
STATIC SP            := 0

FUNCTION EDIT_INIT()
   AADD(Stack,ARRAY(18))
   SP ++
   // vorbelegen
   EDIT_LEER()
RETURN (SP)                                                 // return nThread

PROCEDURE EDIT_EXIT(nThread)
LOCAL iMax
   ADEL(Stack,nThread)
   DO WHILE .T.
      iMax := LEN(Stack)
      IF iMax = 0
         EXIT
      ELSEIF Stack[iMax] = NIL
         ASIZE(Stack,LEN(Stack) - 1)
      ELSE
         EXIT
      ENDIF
   ENDDO
   SP := LEN(Stack)
RETURN

STATIC PROCEDURE EDIT_LEER()
   mARTIST     := " "
...
   aEditControls := {}
   hWndEdit      := 0
RETURN

PROCEDURE EDIT_STORE(nRecno,nThread)
FIELD ARTIST  // use FIELD ... while no Alias
...
   IF PCOUNT() = 2
      // switch to n-Dim
      SP := nThread
      mEditRec := nRecno
      // STORE Data from DBF into Array
      mARTIST     := ARTIST
...
      aEditControls := EditControls

   ELSE
   ENDIF

RETURN

STATIC PROCEDURE ST_REPLACE(nThread)
FIELD ARTIST  // use FIELD ... while no Alias
...
   // lese SLE in mVARs ein
   // passiert durch :datalink
   SP := nThread

   GOTO(mEditRec)
   * REF2GETS(aEditcontrols)
   Gather(aEditcontrols)

   IF (DBRLOCK(mEditRec))
      FIELD->ARTIST     := mARTIST
...
      (DBRUNLOCK(mEditRec))
      SP_LEDIT(.T.)
   ELSE
      MSGBOX("RLock fail")
   ENDIF
RETURN

FUNCTION WM9EDIT(oParent,nThread,oBrowBrow)
...
   oDlg               := NewForm():new(AppDeskTop(),oParent,aPos,aSize,,.F.)
...
   oDlg:cargo := nThread   // Store Thread ID into :Cargo
   oDlg:create()
   AADD(aControls,oDlg)
   hWndEdit := oDlg:getHWND()
...
   oArtist              := XbpSLE():new(oXbp1,,{84,216},{132,24},;
                                                            {{XBP_PP_BGCLR,XBPSYSCLR_ENTRYFIELD}})
   oArtist:bufferLength := 30
   oArtist:tabStop      := .T.
   oArtist:dataLink     := VAR2BLOCK(@mARTIST)
   oArtist:create():setData()
   AADD(aEditControls,oArtist)
...
RETURN

FUNCTION SP_ARTIST(cValue)                                // can be called from "outside"
   IF PCOUNT() > 0
      mARTIST := cValue
   ENDIF
RETURN (mARTIST)
so das wäre so ein "Gerüst" was ich für "MDI" Mandanten nehmen würde.
gruss by OHR
Jimmy
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14658
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: Thread und dbf

Beitrag von Jan »

Hallo Jimmy,

Danke für die ausführliche Antwort. Da muß ich mich erstmal durcharbeiten.

Aber um ein paar Deiner Fragen zu beantworten: Ja, es geht um Mandanten. Jeder Mandant hat sein eigenes Verzeichnis, das die kompletten Datenbanken enthält. Dieses Verzeichnis wird über "Set Default To" zum Daten-Standardverzeichnis erklärt.

Da meine Projekte immer in viele Threads unterteilt sind wird auch ein Import-Modul in einem extra Thread gestartet. Hierbei besteht die Möglichkeit, die neuen Daten dem aktuell geöffneten Mandanten hinzuzufügen (dann habe ich natürlich keinerlei Probleme), oder ob die in einen neu zu erzeugenden eingelesen werden. Und da liegt die Schwierigkeit. Wenn ich die in einen neuen Mandanten einlese: Wie aktualisiere ich alle anderen Threads (wobei es hauptsächlich nur um einen fest definierten geht) mit diesem neuen Mandanten mit seinem Datenverzeichnis?

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Re: Thread und dbf

Beitrag von AUGE_OHR »

Jan hat geschrieben:Dieses Verzeichnis wird über "Set Default To" zum Daten-Standardverzeichnis erklärt.
das ist einer der Gründe warum ich sage "voller" Path, den wie willst du "das" für 2 oder mehr Mandanten gleichzeitig machen ?
Jan hat geschrieben:Wenn ich die in einen neuen Mandanten einlese: Wie aktualisiere ich alle anderen Threads (wobei es hauptsächlich nur um einen fest definierten geht) mit diesem neuen Mandanten mit seinem Datenverzeichnis?
siehe doch jeden Thread als ein Array an und mehrere Threads als n-Dim Array dann bist du praktisch bei meinem Vorschlag.

das #xtranslate hilft dir dabei dich in einem Thread = Array Ebene zu bewegen als wenn du nur einen Thread hättest,
aber du kannst auch ein AEVAL() (oder FOR/NEXT) über "alle Threads" machen wenn du die Objecte in ein Array übernimmst.

die ThreadID (bekommst du mit ThreadInfo() ) ist ja "eindeutig" z.b. für ein ASCAN() zum identifizieren welche Array Ebene gemeint ist.


vergessen hatte ich nun die NET_USE() der 2 Parameter hat : DBFname, nThreadID (= Mandant)
wobei "passend" zur DBF in der NET_USE() auch gleich die Index Datei(en) geöffnet werden.

Code: Alles auswählen

PROCEDURE NET_USE(DBFname, nThreadID)
...
  nPosi := ASCAN(Sp_AllThread(),{|x| x[myThreadID] = nThreadID }  )
  IF nPosi > 0
      // damit schalte ich auf die entsprechende Array Ebene = Thread
      SP_Dim(nPosi)
      // alles im Netz SHARED
      DO CASE
           CASE DBFname = "BlaBla" 
              USE (Sp_Mandant()+DBFname+".DBF") ALIAS DBFname VIA ... SHARED 
              SET INDEX TO Sp_Mandant()+x1,Sp_Mandant()+x2,Sp_Mandant()+x3
gruss by OHR
Jimmy
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21200
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 210 Mal
Danksagung erhalten: 67 Mal

Re: Thread und dbf

Beitrag von Manfred »

Hi Jan,

jetzt kommt wieder das leidige Thema: mache Klassen und bilde Instanzen.

Jede Instanz weiß auf welche Datenbank sie wann und wo zugreifen muß. Da ist es Wurscht, welchen Thread du benutzt. Vergebe für jede Instanz einen evtl. anderen Pfad und schon paßt es. Ich habe nichts mit Default Pfad für Datenbanken usw.
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
Jan
Marvin
Marvin
Beiträge: 14658
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: Thread und dbf

Beitrag von Jan »

Hallo Ihr beiden,

erstmal Manfred: Dein Vorschlag mag die Lösung sein. Aber Du kennst mich und die Klassen - zwei Welten prallen aufeinander. Das wird zumindest kurzfristig nichts werden. Außer Du schreibst mir das "mal eben" :wink: .

Jimmy: Ich kann mit Set Default To arbeiten, weil immer nur ein einziger Mandant geöffnet ist. Immer. Und wenn ich wechsle (es gibt einen Menüpunkt, über den man das über den XbpFileDialog machen kann), so mache ich das, indem ich den Pfad ändere und als Default setze. Und ansonsten, wie gesagt, ich werde mir Dein Beispiel näher ansehen. Das mit dem Array ist eine interessante Idee. Allerdings ist der Thread, in dem ich die dbf ändern muß, immer der gleiche. Ich brauche nicht danach zu suchen. Und ansonsten kann ich mir das ab SL1 auch einfacher machen, da ich einem Thread ja einen eindeutigen Nnamen geben kann, den ich dann direkt ansprechen kann.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Re: Thread und dbf

Beitrag von AUGE_OHR »

hi,

@Manfred : ja man könnte es auch als Class ansehen und die beiden STATIC wären dann CLASS Var
Es ist nur so das man eine Class ja erst create()n muss bevor man sie "benutzen" kann und je
nach Code wäre das "ein Problem" alles umzustellen.

durch das n-Dim und die "eindeutige" ThreadID "sollte" es auch unter MDI keine Probleme machen.

es ist also für "alte" SDI Anwendungen (Cl*pper), die MemVars benutzen, per #define xtranslate
möglich daraus MDI Anwendungen zu machen ohne den "alten" Code komplett zu ändern.
deshalb auch die Procedure Namen : _STORE, _REPLACE, _LEER die noch aus dBase ][ Zeiten stammen.

@Jan
da ich einem Thread ja einen eindeutigen Namen geben kann, den ich dann direkt ansprechen kann.
ja ... wenn du den "erreichst" mit einem PostappEvent() ist es ok.

angenommen man hat seine Application in DLL aufgeteilt und in jeder DLL sind Threads.
Wie soll DLL No.1 das Thread Object aus DLL No2. "kennen" ?

so wie der Formdesigen bei XbpSLE ja ein AADD(editcontrol, oXbp) ausführt um die SLE in ein
Array aufzunehmen, so in der Art nehme ich auch alle "anderen Objecte" in solche Arrays auf.
"Set Default To"
ich weiss nicht mehr warum ... (Nebeneffekte ... ?), aber ich habe das zu Cl*pper Zeiten "raus geschmissen" und es durch den "kompletten Path" ersetzt.

... angenommen die Application läuft im Netzwerk. Die Daten sind auf dem Server und die Application wird local gestartet.
So nun ist der Server aber gar nicht physikalisch "vor Ort" sondern eine Remote "Freigabe" eines anderen PC.
mit einem "vollen" Path bekomme ich den Zugriff auf die DBF / Index Dateien, aber IMHO ein
"Set Default To"
wird nicht auf den Remote PC "wirken", oder ?
gruss by OHR
Jimmy
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14658
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 88 Mal
Kontaktdaten:

Re: Thread und dbf [Erledigt]

Beitrag von Jan »

Es gibt sicher einen eleganteren Weg. Aber so habe ich das jetzt gemacht:

Der Datenpfad wurde ohnehin in einer Public gespeichert, da ich den an den verschiedensten Stellen immer wieder benötige.

Ich habe eine weitere boolsche Public eingebaut, die speichert, ob in einem anderen Thraed der Pfad geändert wurde. Beim Aufruf einer Tabpage (und damit des entsprechenden Threads) wird nun kontrolliert, ob diese Public auf .T. steht. Wenn ja, wird Set Default To mit der aktuellen Datenpfad-Public belegt, alle Datenbanken werden geschlossen und mit der neuen Pfadangabe wieder geöffnet.

Funktioniert einwandfrei.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Antworten