Seite 1 von 2

aktuelles Element einer LinkedList()

Verfasst: 12.05.2014 11:53
von stab
Hallo,

lt. Hilfe gibt es ja mind. 2 Möglichkeiten, sich ein Element in einer LinkedList() merken zu wollen.

Code: Alles auswählen

*Old_Element = @mylist()   ; Ermittelt die Adresse des aktuellen Elements
ChangeCurrentElement(mylist(), *Old_Element) ; Wiederherstellen des letzten aktuellen Elements (von vor der Suche)
und mittels

Code: Alles auswählen

PushListPosition(Numbers())
PopListPosition(Numbers())
Gibt es bei den Methoden entscheidende Vor- und Nachteile?

Danke, danke !!

Re: aktuelles Element einer LinkedList()

Verfasst: 12.05.2014 12:00
von Kiffi
hier noch die dritte:

Code: Alles auswählen

ListIndex = ListIndex(Numbers())
SelectElement(Numbers(), ListIndex)
zu Vor- und Nachteilen kann ich nichts sagen.

Grüße ... Kiffi

Re: aktuelles Element einer LinkedList()

Verfasst: 12.05.2014 14:40
von BSP
Hallo stab.

Ich arbeite gerade sehr stark mit Listen und kann vielleicht etwas dazu sagen:
Ich bastel gerad (mal wieder) an einem Steuerprg. für meine Modelbahn.
Früher habe ich das mit Arrays gemacht, nun benutze ich mal Listen.
Aber ich gestehe, das nächste mal mache ich das wieder mit Arrays.

Du kannst Dir immer nur den Zeiger oder die Nummer auf das Element merken, das gerade aktuell ist.
(Aber das ist bei Listen grundsätzlich so).
Mein_drittes_element = @Liste
Oder:
Mein_drittes_element = ListIndex(Liste())
Was aber, wenn gerade das 5te Element aktuell ist?

Zur Frage:
PushListPosition(Numbers())
PopListPosition(Numbers())

Diese Anweisungen arbeiten mit einem Stapel.
Das heisst:
Das zuletzt gemerkte wird als erstes wieder hergestellt.
Das zu verstehen ist wichtig.
Du kannst damit kein Element direkt anspringen und wiederherstellen.
Verzählst Du Dich beim wiederherstellen, landes Du in einem falschen Element und suchst Dich bei der Fehlerfindung tot.
Ich persönlich benutze das garnicht.

*Old_Element = @mylist() ; Ermittelt die Adresse des aktuellen Elements
ChangeCurrentElement(mylist(), *Old_Element) ; Wiederherstellen des letzten aktuellen Elements (von vor der Suche)

Diese Möglichkeit ist sehr schnell, da Du ein Element „direkt“ anspringen kannst.
Es arbeitet mit Zeigern auf den Speicherort im Pc, wo die Elemente sich befinden.
Diese Zeiger musst Du Dir ermitteln und merken. (*Old_Element = @mylist())
Du solltest sie z.B. nicht speichern, da die Zeiger in einem späteren Neustart des Prg wahrscheinlich nicht mehr stimmen.
Das Prg legt die Liste vielleicht an einem ander Ort im Speicher ab und dann stimmen die Zeiger nicht mehr.
Du musst die Adressen nach einem Prg- Start neu ermitteln und eventuell bei Bedarf in einer weiteren Liste (einem Array ?) speichern.

ChangeCurrentElement(mylist(), *Old_Element) konntroliert nicht, ob es das Element gibt.
Es geht ja auch „ChangeCurrentElement(mylist(), 0)
Dann kann es an anderen Stellen im Prg zum Absturz kommen, und dann heraus zu finden, wo Deine Zeiger falsch eingestellt wurden, kann sehr schwer werden.

Ich arbeite z.Z. mit mehreren Listen deren Elemente auch noch abhängigkeiten zueinander haben.
Daher finde ich es teilweise sehr unübersichtlich, jedesmal
ChangeCurrentElement(mylist(),Mein_xtes_element)
aufzurufen. Oder die gesuchten Elemente erst einmal zu ermitteln.

If SelectElement(Numbers(), ListIndex)
Hat den Vorteil, Du kannst damit direkt das xte Element anspringen. (So vorhanden).
Das dritte Element ist immer das Dritte, egal wo die Liste im Speicher ist.
Die Methode ist aber langsamer, weil die Liste intern jedesmal durchlaufen wird, bis das gewünschte Element erreicht ist.
Diese Nummern kannst Du aber speichern.

Gruß : Bernd

Re: aktuelles Element einer LinkedList()

Verfasst: 12.05.2014 15:01
von ts-soft
Eine weitere Möglichkeit, die aber nur bedingt passt, wäre das Beispiel aus der Hilfe:
Verwendung einer Map zur Indexierung einer verketteten Liste
zu finden im "Einsteiger-Kapitel".
Entspricht mehr oder weniger aber der SelectElement Variante, aber etwas komfortabler :wink:

Gruß
Thomas

Re: aktuelles Element einer LinkedList()

Verfasst: 13.05.2014 10:28
von stab
Danke für die Antworten. Mittels PUSH und POP sollte es dann funktionieren.

Meine Intention:

Ich fülle 3 Listen mit Dateiinformationen aus einem Netzwerk.
Dies können 1ne oder auch 1000 sein.
Danach werden Informationen aus den Listen nacheinander abgerufen.
Da Netzwerk = manchmal lansam dauert dieser Vorgang entsprechend.
Ich möchte diese Listen gerne im Thread füllen und gleichzeitig schon mit der Abarbeitung der Listen beginnen.
Dazu muss ich mir halt das jeweilige Element merken, um die Reihenfolge einzuhalten. Ich denke, das bekomme ich auch hin.

Ich habe es nur noch nicht geschafft, eine LinkedList() einer ThreadProzedur zu übergeben.
Ich kann es zwar auch anders lösen, fände es aber geschickter und würde auch gerne wissen, wie es geht.
Das sollte doch mittels einer Structure gehen. Einfache Beispiele finde ich aber nicht.
Kann mir jemand einen Link geben oder ganz einfach die Übergabe mal zeigen?

Danke!

Re: aktuelles Element einer LinkedList()

Verfasst: 13.05.2014 11:18
von ts-soft
stab hat geschrieben:Ich habe es nur noch nicht geschafft, eine LinkedList() einer ThreadProzedur zu übergeben.
Das macht ja auch nicht unbedingt Sinn. Da die Liste sowieso per Mutex gesichert werden muß, damit nur ein Thread
zur selben Zeit darauf zugreifen kann, spricht nichts dagegen, eine globale oder shared Liste zu nutzen.

Gruß
Thomas

Re: aktuelles Element einer LinkedList()

Verfasst: 13.05.2014 11:39
von Deluxe0321
Als bsp für eine queue (copy & pasta aus projekt - entschuldigt mögliche nicht abgefangene fehler):

Code: Alles auswählen

DeclareModule Processor
  
  Enumeration ;CMD
    #CMD_FIRST
    #CMD_RUN
    #CMD_LOAD
    #CMD_BUILD
    #CMD_GET
    #CMD_POST
    #CMD_END
    #CMD_LAST
  EndEnumeration
  
  Enumeration ;TStatus
    #STATUS_ON
    #STATUS_OFF
  EndEnumeration  
    
  Declare Init()
  
  Declare PostCMD(Handle.i,CMD.i,*UserData = 0)
  
  Declare Release(Handle.i,Wait.i = #True)
  
EndDeclareModule

Module Processor
  
  ;{ - internal
  Structure List_MyList
    CMD.i
    *Data
  EndStructure
  
  Structure Processor
    HSemaphore.i
    HMutex.i
    TStatus.i
    TThreadID.i
    List LElements.List_MyList() ;< -- liste
  EndStructure

  Macro IsHandle() 
    If Not Handle.i : ProcedureReturn #False : EndIf 
  EndMacro
  
  Procedure Processor(*Processor.Processor)
    
    Protected SElement.List_MyList
    Protected HSemaphore.i, HMutex.i
    
    If Not *Processor
      ProcedureReturn #False  
    EndIf    
    
    LockMutex(*Processor\HMutex.i)
      *Processor\TStatus.i = #STATUS_ON
    UnlockMutex(*Processor\HMutex.i)
    
    Debug "Processor starting.."
    
    Repeat
      
      Debug "<-- Waiting for CMD :)"
      
      WaitSemaphore(*Processor\HSemaphore.i)
      
      LockMutex(*Processor\HMutex.i)
        ResetList(*Processor\LElements())
        FirstElement(*Processor\LElements())
        CopyStructure(@*Processor\LElements(),@SElement,List_MyList)
        DeleteElement(*Processor\LElements())
      UnlockMutex(*Processor\HMutex)
      
      Select SElement\CMD.i
        Case  #CMD_RUN
          Debug " --> #CMD_RUN"
          ;delay um etwas "workload" zu simulieren
          Delay(2000)
        Case  #CMD_LOAD
          Debug " --> #CMD_LOAD"
          ;delay um etwas "workload" zu simulieren
          Delay(300)
          
        Case  #CMD_BUILD
          Debug " --> #CMD_BUILD"
          ;delay um etwas "workload" zu simulieren
          Delay(6000)          
          
        Case  #CMD_END  
          Debug " --> #CMD_END --> ENDE!"
          
          LockMutex(*Processor\HMutex.i)
            *Processor\TStatus.i = #STATUS_OFF
          UnlockMutex(*Processor\HMutex.i)
          
          Debug "<-- ending now.."
          
          Break
          
      EndSelect
      
    ForEver
    
    
  EndProcedure
  
  ;} - internal
  
  Procedure Init()
    
    *Processor.Processor = AllocateMemory(SizeOf(Processor))
    
    If Not *Processor : ProcedureReturn #False : EndIf
    
    InitializeStructure(*Processor,Processor)
    
    *Processor\HMutex     = CreateMutex()
    *Processor\HSemaphore = CreateSemaphore()
    
    ;start thread
    *Processor\TThreadID.i = CreateThread(@Processor(),*Processor)
    
    If Not *Processor\TThreadID.i
      FreeMutex(*Processor\HMutex.i)
      FreeSemaphore(*Processor\HSemaphore.i)
      ClearStructure(*Processor,Processor)
      FreeMemory(*Processor)
    EndIf
    
    ProcedureReturn *Processor
    
  EndProcedure  
  
  Procedure PostCMD(Handle.i,CMD.i,*UserData = 0)
    
    IsHandle()
    
    If Not (CMD.i > #CMD_FIRST And CMD.i < #CMD_LAST) 
      ProcedureReturn #False 
    EndIf
    
    Protected *Processor.Processor = Handle.i
    
    LockMutex(*Processor\HMutex)
      If AddElement(*Processor\LElements())
        With *Processor\LElements()
          \CMD.i = CMD.i 
          \Data  = *UserData
        EndWith
      Else
        UnlockMutex(*Processor\HMutex)
        ProcedureReturn #False
      EndIf
      
    UnlockMutex(*Processor\HMutex)
    
    SignalSemaphore(*Processor\HSemaphore.i)
    
    ProcedureReturn #True
    
  EndProcedure
  
  Procedure Release(Handle.i,FinishQueue.i = #True)
    
    IsHandle()
    
    Protected *Processor.Processor = Handle.i
    
    If Not Wait.i
      LockMutex(*Processor\HMutex.i)
        ClearList(*Processor\LElements())
      UnlockMutex(*Processor\HMutex.i)
    EndIf

    ;"ende" senden
    PostCMD(*Processor,#CMD_END)    

    While IsThread(*Processor\TThreadID.i)
      Delay(10)
    Wend 
    
    FreeMutex(*Processor\HMutex.i)
    FreeSemaphore(*Processor\HSemaphore.i)
    
    ClearStructure(*Processor,Processor)
    FreeMemory(*Processor)
    
    Debug "release done!"
    
    ProcedureReturn #True
    
  EndProcedure  
  
  
EndModule


Process = Processor::Init()

If Not Process : End : EndIf
  
OpenConsole("Queue Test")
Repeat
  
  PrintN("CMD: (type them) -->  run, load, build, end") 
  
  Line.s = Input()
  
  Select LCase(Line.s)
    Case "run"
      Processor::PostCMD(Process,Processor::#CMD_RUN)
      PrintN(" --> RUN send, check debug output..") : PrintN("")
    Case "load"
      Processor::PostCMD(Process,Processor::#CMD_LOAD)
      PrintN(" --> LOAD send, check debug output..") : PrintN("")
    Case "build"
      Processor::PostCMD(Process,Processor::#CMD_BUILD)
      PrintN(" --> BUILD send, check debug output..") : PrintN("")
    Case "end"
      PrintN(" --> END send, check debug output..")
      If Processor::Release(Process)
        Break  
      EndIf
    Default
      PrintN("kenne ich nicht =P")
  EndSelect
  
ForEver
Grüße

Re: aktuelles Element einer LinkedList()

Verfasst: 13.05.2014 11:56
von NicTheQuick
Mit einer ConcurrentQueue kann ich auch dienen: Video: [PB] HowTo: ConcurrentQueue. Und hier noch mal auf meiner Seite: Wie schreibe ich eine ConcurrentQueue.

Re: aktuelles Element einer LinkedList()

Verfasst: 14.05.2014 17:33
von stab
Hallo,

danke noch mal für die Tipps.
Das Video von NicTheQuick hatte ich mir schon vorher mal angesehen und gestaunt, wie einfach doch programmieren sein kann.
Ich bekomme aber schon Stirnrunzeln, wenn ich die zwei "::" sehe, kann damit garnichts anfangen und weiß auch nicht, ob das in den Anfängerbereich gehört. Ich finde dazu auch nichts in der Hilfe. Suchen kann man danach jedenfalls nicht. Vielleicht zeigt mir jemand mal, wo das erklärt wird.

Warum nicht Listen in eine ThreadProzedur übergeben?
Ich finde, das macht schon Sinn. Wenn ich 10 Listen bearbeiten will, müsste ich ja 10 Prozeduren anlegen. Bei einer Programmänderung ganz schön aufwendig.

Also, was ich gesucht habe war ein simples Beispiel für Anfänger, nach langem probieren hat es dann geklappt:

Code: Alles auswählen

Structure mitlisten
   List zahlen.l()
EndStructure

Procedure ListeImThread(*zeiger.mitlisten)
    LastElement(*zeiger\zahlen())
    AddElement(*zeiger\zahlen())
    *zeiger\zahlen() = 1
EndProcedure
  
Define.mitlisten adresse
  
CreateThread(@ListeImThread(),@adresse)
  
; etc
Daraus gemacht habe ich folgendes:

Code: Alles auswählen


Structure mitlisten
   List zahlen.l()
   List namen$()
   ; usw
EndStructure

Global listposition = 0
Global MaxListgroesse = 20

Procedure ListeImThread(*zeiger.mitlisten)
  For z = 0 To MaxListgroesse -1
    d.l = Random(3,1)*1000
    Delay (d)
    LastElement(*zeiger\zahlen())
    AddElement(*zeiger\zahlen())
    *zeiger\zahlen() = d + z
    Debug "neuer Wert nach: "  + Str(d/1000) + " Sekunden:  " + Str(d+z)
  Next
  
  ; z.B noch weitere Listen bearbeiten
  AddElement(*zeiger\namen$()) : *zeiger\namen$() = "Willi"
  AddElement(*zeiger\namen$()) : *zeiger\namen$() = "Moritz"
    
EndProcedure
  
Define.mitlisten adresse
  
CreateThread(@ListeImThread(),@adresse)
  
Procedure leseListe(List z.l())
  If ListIndex(z()) =  MaxListgroesse -1
    listposition = 0
  EndIf  
  If ListSize(z()) > listposition
    SelectElement(z(), listposition)
    Debug "Juhu: " + Str(z())
    listposition +1
  Else
    Debug "Mist! Nichts neues!"
  EndIf
EndProcedure
  
Repeat
  leseListe(adresse\zahlen())
  Delay(1500)
ForEver
Die Liste wird im Hintergrund gefüllt. Mal schneller, mal langsamer.
Ich kann aber schon daraus lesen, sofern Elemente vorhanden sind.

Bisher hat es funktioniert.
Oder spricht irgendwas dagegen, das so umzusetzen?

vg stab

Re: aktuelles Element einer LinkedList()

Verfasst: 14.05.2014 17:35
von stab
Ich sehe gerade, habe Quote mit Code verwechselt.
Sorry.