Seite 1 von 1

Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 06.08.2016 22:11
von schleicher
Ich habe mal einen Beispielcode geschrieben, wo das Problem auftaucht. Wenn in der Foreach-Schleife selected_movies() ein gestarteteter Thread mit WaitThread warten soll, dann kann ich mir nicht erklären, warum PostEvent dann nichts mehr an mein Progressbargadget und Stringgadget sendet . Auch reagiert der gestartete Thread nicht sauber. (FTPProgess - Ende oder Error)
Der Code ist warscheinlich nicht so sauber aber ich lerne halt

Wo liegt der Fehler ?

Code: Alles auswählen

EnableExplicit

Structure Ordner
  Ordner.s
  Ordnername.s
  Ordnerstartdatei.s
  Date.s
  Size.s
EndStructure
Global NewList Ordner.Ordner()

Structure geraetepfad
  pfad.s
  id.l
EndStructure

Structure procedureparameter
  moviename_ori.s
  moviename.s
  pfad_enigma.s
  pfad_to.s
  progress.l
  size.l
EndStructure

Structure info_distant 
  chmod_raw.s
  chmod.s
  Name.s 
  Name_ori.s
  size.s 
  size_byte.s
  Dat.s 
  Type.l
  Type2.l
  Chemin.s 
  link.s
  Repertoire_distant.s 
EndStructure
Global NewList info_distant.info_distant()

Structure selected_movies
  Name.s 
  Name_ori.s
  sizekb.s
  sizemb.s
  path.s
EndStructure
Global NewList selected_movies.selected_movies()

Enumeration Window
  #Window_Main
EndEnumeration

Enumeration Gadget
  #Listicon_movie
  #Button_connect
  #Button_Copy_Movie
  #String_copy_info
  #ProgressBar_Movie
EndEnumeration

Enumeration
  #ftp
EndEnumeration

; Custom events
Enumeration #PB_Event_FirstCustomValue
  #Event_Progress
EndEnumeration 

Declare   Main()
Declare   list_ftp_movie(*Parameters.geraetepfad)
Declare.s filter_datum_movie(movie.s)
Declare.s Sonderzeichen_vom_Server(string_orginal.s)
Declare   copy_movie()
Declare   copymovie_from_server(*memmovie.Procedureparameter)
Declare   Event_Progress()

Global IP.s = "192.168.40.29"                                                        ;hier IP, User, Pass, Ftp_port anpassen 
Global User.s = "root"
Global Pass.s = ""
Global ftp_port = 21
Global dir.s , datum_zeit.s,   string_umgewandelt.s
Define.s Progresstext
Define.l Progresswert_ist 


Main()
Procedure Main()
  Protected event
  Protected thread
  Protected *Parameters.geraetepfad
  
  OpenWindow(#Window_Main, 0, 0, 950, 650, "Test_Copy_movie", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ListIconGadget(#Listicon_movie, 0, 80, 690, 570, "Moviename", 400, #PB_ListIcon_CheckBoxes | #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
  AddGadgetColumn(#Listicon_movie, 1, "Datum/Zeit", 140)
  AddGadgetColumn(#Listicon_movie, 1, "Größe", 150)
  ButtonGadget(#Button_connect, 710, 20, 220, 40, "Connect to server")
  ButtonGadget(#Button_Copy_Movie, 710, 600, 220, 40, "Copy")
  StringGadget(#String_copy_info, 0, 40, 690, 30, "")
  ProgressBarGadget(#ProgressBar_Movie, 0, 10, 690, 20, 0, 100)
  
  BindEvent(#Event_Progress, @Event_Progress())
  
  Repeat
    Event=WaitWindowEvent()
    Select Event
      Case #PB_Event_CloseWindow
        CloseWindow(#Window_Main)
        End
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Button_connect
           
            InitNetwork()
            If OpenFTP(#Ftp, IP, User, Pass, ftp_port)<>0
              Debug "Connection ok"
              Repeat
                *Parameters.geraetepfad = AllocateMemory(SizeOf(geraetepfad))
                If *Parameters.geraetepfad = 0
                  Delay(1000)
                EndIf
              Until *Parameters.geraetepfad
              *Parameters\pfad="/media/hdd/movie/"                                                  ; hier eventuell pfad anpassen 
              thread=CreateThread(@list_ftp_movie(), *Parameters.geraetepfad)
              If thread
                Debug "thread gestartet"  
              EndIf
              
            Else
              MessageRequester("Error", "Can ot connecting", #MB_ICONERROR)
            EndIf
            
            
          Case #Listicon_movie 
            
            
          Case #Button_Copy_Movie
            Protected  Filmdate.s, moviename.s, moviename_1.s, y, a
            Protected thread_copy, Filmname.s, moviepath.s, sizekb.s
            ClearList(selected_movies())
            Select EventType()
                
              Case #PB_EventType_LeftClick
                
                For a=0 To CountGadgetItems(#ListIcon_Movie)
                  
                  If GetGadgetItemState(#ListIcon_Movie, a)=#PB_ListIcon_Checked
                    Filmname=GetGadgetItemText(#ListIcon_Movie, a, 0)
                    Filmdate=GetGadgetItemText(#ListIcon_Movie, a, 2)
                    
                    ForEach info_distant()
                      If FindString(info_distant()\name , Filmname) And info_distant()\Dat=Filmdate
                        If Not Right(info_distant()\Name.s, 4)="cuts"
                          moviename=info_distant()\Name
                          moviepath=info_distant()\Chemin
                          moviename_1=info_distant()\Name_ori
                          sizekb=info_distant()\size
                          
                          AddElement(selected_movies())
                          selected_movies()\Name=moviename
                          selected_movies()\Name_ori=moviename_1
                          selected_movies()\path=moviepath
                          selected_movies()\sizekb=sizekb
                        EndIf
                      EndIf
                    Next
                    
                    If ListSize(selected_movies())>0
                      copy_movie()
                    EndIf
                    
                  EndIf 
                Next a
                
            EndSelect
        EndSelect  
    EndSelect
  ForEver 
EndProcedure

Procedure list_ftp_movie(*Parameters.geraetepfad)
  Protected Listtext.s
  Protected movie.s, f$, string_orginal.s, string_umgewandelt.s
  Protected dir$=*Parameters\pfad
  Protected gadgettyp.s
  Protected image.i
  Protected Stringtext.s
  Protected moviename.s
  Protected datum_zeit.s
  Protected sizemb
  Shared Progresswert_ist , Progresstext
  
 ClearList(info_distant())
  
  If IsFTP(#Ftp)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      dir$=RemoveString(dir$,"|x|--->" )
    CompilerElse
    CompilerEndIf
    
    SetFTPDirectory(#ftp,dir$)
    If ExamineFTPDirectory(#ftp)
      While NextFTPDirectoryEntry(#ftp)  
        
        f$=""
        f$= FTPDirectoryEntryRaw(#Ftp)
        f$=ReplaceString(f$,Chr(32),",") :f$=ReplaceString(f$,",,,,,",","):f$=ReplaceString(f$,",,,,",","):f$=ReplaceString(f$,",,,",","):f$=ReplaceString(f$,",,",","):
        
        AddElement(info_distant()):
        info_distant()\size.s=Str(FTPDirectoryEntrySize(#ftp)/1024)
        info_distant()\size_byte=Str(FTPDirectoryEntrySize(#ftp))
        info_distant()\dat.s=StringField(f$,6,",")+" "+StringField(f$,7," ")+","+StringField(f$,8,",")
        info_distant()\type.l=Val(StringField(f$,2,","))
        info_distant()\link.s=StringField(f$,11,",")
        info_distant()\Name_ori = FTPDirectoryEntryName(#ftp)
        If Right(info_distant()\name.s, 1)= "-":info_distant()\name.s = RTrim(info_distant()\name.s,"-"):EndIf
        string_orginal.s=info_distant()\Name_ori
        string_umgewandelt=Sonderzeichen_vom_Server(string_orginal.s)
        info_distant()\Name=string_umgewandelt.s
        info_distant()\Chemin=dir$
        If Not Right(info_distant()\Chemin, 1)="/"
          info_distant()\Chemin+"/"
        EndIf
        datum_zeit=info_distant()\Dat
        If info_distant()\Name_ori.s=".." Or info_distant()\Name_ori.s="."
          info_distant()\size.s="0"
          info_distant()\type.l=888
          
        EndIf
        If  info_distant()\type.l=2  
          Progresstext= "Analyze  " + dir$
          AddElement(Ordner())
          Ordner()\Ordner=dir$+info_distant()\Name_ori
        EndIf
        
        If info_distant()\type.l=1  And Not info_distant()\chmod.s="L777"
          
          movie=info_distant()\name.s
          sizemb=Val(info_distant()\size)/1024
          moviename=movie
          
          If GetExtensionPart(movie)="ts"
            datum_zeit=filter_datum_movie(movie)
            info_distant()\Dat=datum_zeit
            moviename=Mid(moviename, 16)
            Progresstext="Add :"+  moviename+ " from "+ dir$
            Progresswert_ist=0
            PostEvent(#Event_Progress)
            AddGadgetItem(#Listicon_movie, -1, moviename + Chr(10) + sizemb + Chr(10) + datum_zeit)
            
          ElseIf GetExtensionPart(movie)="mp4" 
            
            Progresstext="Add :"+  moviename+ " from "+ dir$
            AddGadgetItem(#Listicon_movie, -1, moviename + Chr(10) + sizemb + Chr(10) + datum_zeit)
            
          ElseIf  GetExtensionPart(movie)="flv" 
            Progresstext="Add :"+  moviename+ " from "+ dir$
            Progresswert_ist=0
            PostEvent(#Event_Progress)
            AddGadgetItem(#Listicon_movie, -1, moviename + Chr(10) + sizemb + Chr(10) + datum_zeit)
            
          ElseIf  GetExtensionPart(movie)="mkv" 
            Progresstext="Add :"+  moviename+ " from "+ dir$
            Progresswert_ist=0
            PostEvent(#Event_Progress)
            AddGadgetItem(#Listicon_movie, -1, moviename + Chr(10) + sizemb + Chr(10) + datum_zeit)
          EndIf
        EndIf
      Wend
      FinishFTPDirectory(#ftp)
      Progresstext="Finish"
      Progresswert_ist=0
      PostEvent(#Event_Progress)
      ResetList(info_distant())
      
      SortStructuredList(info_distant(), #PB_Sort_Descending, OffsetOf(info_distant\Name), TypeOf(info_distant\Name))
      
      ForEach info_distant()
        If info_distant()\Name_ori.s=".." Or info_distant()\Name_ori="."
          DeleteElement(info_distant())
        EndIf
      Next
      
      
    EndIf
  Else
    MessageRequester("Info","Connection Closed !",#MB_OK|#MB_ICONINFORMATION|#MB_DEFBUTTON1|#MB_APPLMODAL) 
  EndIf
  
  
  
EndProcedure

Procedure.s filter_datum_movie(movie.s)
  Define jahr.s, monat.s, tag.s, stunde.s, minute.s
  
  jahr=Mid(movie, 0, 4)
  monat=Mid(movie, 5, 2)
  tag=Mid(movie, 7, 2)
  stunde=Mid(movie, 10, 2)
  minute=Mid(movie, 12, 2)
  
  datum_zeit.s=tag+"."+monat+"."+jahr+" / "+stunde+":"+minute
  ProcedureReturn datum_zeit.s
  
EndProcedure

Procedure.s Sonderzeichen_vom_Server(string_orginal.s)  
  Protected string_orginal1$, string_orginal2$, string_orginal3$, string_orginal4$, string_orginal5$, string_orginal6$, string_orginal7$
  
  string_orginal1$=ReplaceString(string_orginal, "ü", "ü", #PB_String_CaseSensitive) 
  string_orginal2$=ReplaceString(string_orginal1$, "Ü", "Ü", #PB_String_CaseSensitive) 
  string_orginal3$=ReplaceString(string_orginal2$, "Ö", "Ö", #PB_String_CaseSensitive) 
  string_orginal4$=ReplaceString(string_orginal3$, "ö", "ö", #PB_String_CaseSensitive) 
  string_orginal5$=ReplaceString(string_orginal4$, "Ä", "Ä", #PB_String_CaseSensitive) 
  string_orginal6$=ReplaceString(string_orginal5$, "ä", "ä", #PB_String_CaseSensitive)   
  string_orginal7$=ReplaceString(string_orginal6$, "ß", "ß", #PB_String_CaseSensitive)  
  string_umgewandelt.s=string_orginal7$
  ProcedureReturn string_umgewandelt.s
  
EndProcedure  

Procedure copy_movie()
  Protected copypath.s, path.s, movie.s, sizekb.l, *memmovie.Procedureparameter, threadmovie
  copypath=PathRequester("Please select a Folder for copy ", "E:\Filme\")
  If copypath
    ForEach selected_movies()
      
      path=selected_movies()\path
      movie=selected_movies()\Name_ori
      sizekb=Val(selected_movies()\sizekb)
      
      Repeat
        *memmovie.procedureparameter = AllocateMemory(SizeOf(procedureparameter))
        If *memmovie.procedureparameter = 0
          Delay(1000)
        EndIf
      Until *memmovie.procedureparameter
      
      *memmovie\pfad_enigma=path
      *memmovie\moviename_ori=movie
      *memmovie\pfad_to=copypath
      *memmovie\size=sizekb
      
      threadmovie=CreateThread(@copymovie_from_server(), *memmovie)   
      If threadmovie
        Debug "thread copy gestartet"                ;##################################################################################################
       ; WaitThread(threadmovie)                     ;Hier liegt das Problem . Wird WaitThread auskommentiert, das funktioniert PostEvent(  nicht mehr
      EndIf                                          ;##################################################################################################
      
    Next
  EndIf  
  
EndProcedure

Procedure copymovie_from_server(*memmovie.Procedureparameter)
  Shared Progresswert_ist , Progresstext
  Define prozentsatz.l
  Protected Stringtext.s
  Protected gadgettyp.s
  Protected path.s
  Protected movie.s
  Protected copy_to_path.s
  Protected moviename.s
  Protected filetotalbyte
  Protected maxwert, oldprozesswert, oldprozesswert_, istwert, istwert_, progresswert
  ;Progresswert_ist , Progresstext
  
  path=*memmovie\pfad_enigma
  movie=*memmovie\moviename_ori
  copy_to_path=*memmovie\pfad_to
  filetotalbyte=*memmovie\size
  moviename=Sonderzeichen_vom_Server(movie)
  
  Debug path+movie
  Debug copy_to_path+moviename
  
  maxwert=2147483647 ;maxwert in byte
  oldprozesswert=0
  oldprozesswert_=0
  
  If CheckFTPConnection(#ftp)<>0
    Debug "Ftp-verbindung ok"
  Else
    Debug "Ftp muss neu verbunden werden"
    OpenFTP(#ftp, IP, User, Pass, ftp_port)
  EndIf
  
  If ReceiveFTPFile(#ftp, path+movie, copy_to_path+moviename, #True)
    If FTPProgress(#ftp)=#PB_FTP_Started
      Debug "Download gestartet"
      Repeat
        Delay(100)
        istwert=FTPProgress(#ftp)/1024
        If istwert>0
          If Not Left(Str(istwert), 1)="-"
            oldprozesswert=istwert+oldprozesswert_
            progresswert=oldprozesswert
          EndIf
        Else
          If Not istwert=-1 
            If istwert<0
              istwert_=(FTPProgress(#ftp)+maxwert-3)/1024
              progresswert=oldprozesswert+istwert_
              oldprozesswert_=progresswert
            EndIf
          EndIf
        EndIf
        prozentsatz=(progresswert*100)/filetotalbyte
        
        Stringtext="copy : "+Str(prozentsatz)+" % = " +Str(progresswert) + " / "+Str(filetotalbyte) +"  "+moviename
        gadgettyp="String"
        Progresswert_ist =prozentsatz
        Progresstext=Stringtext
        PostEvent(#Event_Progress)
        Debug Progresstext
        
        
        
        Select  FTPProgress(#ftp)
            
          Case #PB_FTP_Error  
            SetGadgetState(#Progressbar_Movie, 0) 
            MessageRequester("Error", "Can Not copy "+ moviename)
            oldprozesswert=0
            oldprozesswert_=0
            Progresswert_ist=0
            Progresstext="Error"
            PostEvent(#Event_Progress)
            Break
          Case #PB_FTP_Finished
            MessageRequester("Info", "Copy Finish "+ movie, #MB_ICONINFORMATION)
            oldprozesswert=0
            oldprozesswert_=0
            Progresswert_ist=0
            Progresstext="Finish"
            PostEvent(#Event_Progress)
            Break
            
        EndSelect
        
      ForEver
    EndIf
  Else
    MessageRequester("Error", "Can Not transfer "+ movie)  
  EndIf
  Debug "Kopiervorgang beendet" 
  
  ClearStructure(*memmovie, Procedureparameter)
  
EndProcedure


Procedure Event_Progress()
  Shared Progresswert_ist , Progresstext
  
  SetGadgetText(#String_copy_Info, Progresstext)
  SetGadgetState(#Progressbar_Movie, Progresswert_ist)
  
EndProcedure

Re: Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 06.08.2016 23:21
von man-in-black
Hi,

erstmal zu deiner groben Struktur. Du kannst zwar PostEvent zur Kommunikation zwischen den Threads nutzen,
musst aber auf die Speicherzugriffe achten. Es geht um die folgenden Variablen:

Code: Alles auswählen

Progresstext=...
Progresswert_ist=...
Soll heißen, dass zur gleichen Zeit nur eine Instanz auf dieselbe Variable zugreifen darf!
Du hast aber 2 Threads, die dies versuchen. Ansonsten kommt es zu Speicherfehlern. (--> Mutex)
Abgesehen davon kann es passieren, dass deine mit dem Event verknüpfte Procedure "Event_Progress" nicht schnell genug aufgerufen wird. In der Zwischenzeit hast du aber deine Variablen neu befüllt. Informationsverlust ...
Besser wäre ein Stack (Liste), auf dem du deine neuen Infos ablegst. "Event_Progress" kann dann in aller Ruhe alles abarbeiten.

Ansonsten weiß ich nicht, WIE du deinen Thread anhältst. Im Code finde ich dazu nichts ...
(WO ist ja mehr oder weniger der Beschreibung entnehmbar)

Und "WaitThread(Thread [, Timeout])" hält den AKTUELLEN Thread an und nicht den als 1. Parameter übergebenen.
Da deine Procedure "copy..." Teil des Hauptthreads ist, wird die Eventverarbeitung angehalten
und somit deine Gadgets nicht aktualisiert.

edit: WIE ist doch enthalten. IDE hat nur die Kommentare nicht mit durchsucht.^^

MFG
MIB

Re: Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 07.08.2016 00:05
von schleicher
Kann deinen Ausführungen leider nicht ganz folgen, denn die beiden unterschiedlichen Threads laufen nie gleichzeitig. Vieleicht habe ich mich im ersten Post falsch ausgedrückt. Es ging in meinem Problem auch nicht darum einen Thread anzuhalten, sondern sondern eine Foreach Schleife anzuhalten, solange ein darin laufender Thread läuft. Das wollte ich ja mit WaitThread machen, doch dann taucht das genannte Problem auf.

Re: Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 07.08.2016 00:15
von mk-soft
In einer Schleife auf eine Thread zu warten macht irgendwie keinen sinn.
Dann kann man auch gleich aus der Schleife eine Unterfunktion aufrufen...

Re: Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 07.08.2016 00:25
von man-in-black
Der Schönheitsfehler:
denn die beiden unterschiedlichen Threads laufen nie gleichzeitig
Sobald du einen Thread via Befehl startest, hast du IMMER 2 Threads laufen.
Einmal den neuen und dann deinen Hauptthread. In diesem Fall sucht dein einer
per FTP deine Bibliothek durch und gibt die Infos über PostEvent an den Hauptthread.
Dieser arbeitet die anfallenden Events ab und startet bei Eingang deines Sonderevents "...Progress..."
die dazugehörige Procedure.
Knackpunkt sind deine geteilten Variablen, die von 2 Seiten abgegriffen werden. /:->

Das eigentliche Problem:
Es ging in meinem Problem auch nicht darum einen Thread anzuhalten, sondern sondern eine Foreach Schleife anzuhalten, solange ein darin laufender Thread läuft. Das wollte ich ja mit WaitThread machen, doch dann taucht das genannte Problem auf
Nochmal, dein Hauptthread ist für die Eventverarbeitung zuständig. Wenn du diesen mit WaitThread anhältst,
wird auch kein ProgressBlaBla() bei Eventeingang aufgerufen.
Vielleicht deutlicher. Dein Hauptthread ruft in sich die Procedure mit deiner Foreach-Schleife auf. Somit ist alles innerhalb dieser Procedure
IMMERNOCH im Hauptthread. Wenn WaitThread die Schleife anhält, wird auch der umgebende Thread gestoppt!
(Wortwiederholungen en mass :D )

Re: Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 07.08.2016 00:29
von schleicher
mk-soft hat geschrieben:In einer Schleife auf eine Thread zu warten macht irgendwie keinen sinn.
Na gut dann werde ich morgen es mal andern.

Re: Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 07.08.2016 00:38
von man-in-black
mk-soft hat geschrieben:
In einer Schleife auf eine Thread zu warten macht irgendwie keinen sinn.

Na gut dann werde ich morgen es mal andern.
Nur so als Hinweis, wenn du das 1zu1 umsetzt und nur CreateThread durch den direkten Funktionsaufruf ersetzt,
wird dein PostEvent() auch nicht richtig abgearbeitet.
Eine Eventsteuerung erfordert immer die Eventabarbeitung. Diese wird von deinem Hauptthread übernommen.
Soll heißen, dass deine Events erst "ankommen", wenn die Unterfunktion schonwieder abgearbeitet ist.
Du musst ergo regelmäßig WindowEvent() aufrufen und prüfen.

Eleganter ist schon die Umsetzung als Thread. Lass dir das nochmal in Ruhe durch den Kopf gehen ;)
Ich weiß jetzt leider auch nicht, wie ich das noch schöner formulieren kann. Sry.

edit:
Wieso packst du nicht bereits copy_movie in einen Thread und nicht erst copymovie_from_server?

MFG
MIB

Re: Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 07.08.2016 10:17
von schleicher
man-in-black hat geschrieben:.

edit:
Wieso packst du nicht bereits copy_movie in einen Thread und nicht erst copymovie_from_server?
Na deinem Post von gestern Abend hatte ich genau an das gedacht. Werde ich heute umsetzen. Danke für den Tip.

Re: Problem PostEvent( in Verbindung mit WaitThread(

Verfasst: 11.08.2016 17:58
von schleicher
Habs gemacht und funktioniert.