Seite 2 von 3

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 05.12.2018 21:46
von ccode_new
mk-soft hat geschrieben:Clipboard funktionen im Thread aufrufen geht nicht sicher.
Eigentlich schon! Nur man kann hierbei ja nicht intern eingreifen.

Woher weiß ich wann die Funktion fertig ist, wenn diese dabei asynchron läuft.

Also eigentlich müsste es heißen:

"Die PureBasic-Clipboard-Funktionen im Thread aufrufen geht unter PureBasic nicht sicher unter Linux."

Aber wofür gibt es den dein tolles Modul. :mrgreen:

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 05.12.2018 22:33
von mk-soft
Alles was mit PostEvent(...) versendet wird läuft im Message-Buffer von PB auf und wird erst beim Aufruf von WaitWindowEvent(...) verarbeitet.
Somit läuft es im Main-Scope.

Code: Alles auswählen

;-TOP

; ***************************************************************************************

;-Begin Of SendEvent

; Comment : SendEvent
; Author  : mk-soft
; Version : v1.06
; Create  : unknown
; Update  : 07.08.2016

;- Structure
Structure udtSendEvent
  Signal.i
  Result.i
  *pData
EndStructure

; ---------------------------------------------------------------------------------------

Procedure SendEvent(Event, Window = 0, Object = 0, EventType = 0, pData = 0, Semaphore = 0)
  
  Protected MyEvent.udtSendEvent, result
  
  With MyEvent
    If Semaphore
      \Signal = Semaphore
    Else
      \Signal = CreateSemaphore()
    EndIf
    \pData = pData
    PostEvent(Event, Window, Object, EventType, @MyEvent)
    WaitSemaphore(\Signal)
    result = \Result
    If Semaphore = 0
      FreeSemaphore(\Signal)
    EndIf
  EndWith
  
  ProcedureReturn result
  
EndProcedure

; ---------------------------------------------------------------------------------------

Procedure SendEventData(*MyEvent.udtSendEvent)
  ProcedureReturn *MyEvent\pData
EndProcedure

; ---------------------------------------------------------------------------------------

Procedure DispatchEvent(*MyEvent.udtSendEvent, result)
  *MyEvent\Result = result
  SignalSemaphore(*MyEvent\Signal)
EndProcedure

;- End Of SendEvent

; ***************************************************************************************

;- Example

EnableExplicit

; Constant
Enumeration ;Window
  #Main
EndEnumeration

Enumeration ; Menu
  #Menu
EndEnumeration

Enumeration ; MenuItems
  #MenuExitApplication
EndEnumeration

Enumeration ; Gadgets
  #List
  #Edit
EndEnumeration

Enumeration ; Statusbar
  #Status
EndEnumeration

; Global Variable
Global ExitApplication

; Functions
Procedure UpdateWindow()
  
  Protected x, y, dx, dy, menu, status
  
  menu = MenuHeight()
  If IsStatusBar(#Status)
    status = StatusBarHeight(#Status)
  Else
    status = 0
  EndIf
  x = 0
  y = 0
  dx = WindowWidth(#Main)
  dy = WindowHeight(#Main) - menu - status
  ResizeGadget(#List, x, y, dx, dy)
  
EndProcedure

; -----------------------------------------------------------------------------

Enumeration EventCustomValue #PB_Event_FirstCustomValue
  #MyEvent_GetClipbord
  #MyEvent_SetClipboard
  #MyEvent_AddText
EndEnumeration

Procedure DoSetClipboard()
  Protected MyEvent, *text.String
  MyEvent = EventData()
  *text = SendEventData(MyEvent)
  SetClipboardText(*text\s)
  DispatchEvent(MyEvent, 1)
EndProcedure

Procedure DoGetClipboard()
  Protected MyEvent, *text.String, len
  MyEvent = EventData()
  *text = SendEventData(MyEvent)
  *text\s = GetClipboardText()
  len = Len(*text\s)
  If len
    ClearClipboard()
  EndIf
  DispatchEvent(MyEvent, len)
EndProcedure

Procedure DoAddText()
  Protected MyEvent, *text.String
  MyEvent = EventData()
  *text = SendEventData(MyEvent)
  AddGadgetItem(#List, -1, *text\s)
  DispatchEvent(MyEvent, 1)
EndProcedure

BindEvent(#MyEvent_GetClipbord, @DoGetClipboard())
BindEvent(#MyEvent_SetClipboard, @DoSetClipboard())
BindEvent(#MyEvent_AddText, @DoAddText())

; -----------------------------------------------------------------------------

Structure udtThread
  ThreadID.i
  Exit.i
EndStructure

Global Thread1.udtThread

Procedure thWork(*data.udtThread)
  Protected result, text.string
  
  Repeat
    result = SendEvent(#MyEvent_GetClipbord, 0, 0, 0, text)
    If result
      SendEvent(#MyEvent_AddText, 0, 0, 0, text)
    EndIf
    Delay(1000)
  Until *data\Exit
  
EndProcedure

; -----------------------------------------------------------------------------

; Main
Procedure Main()
  
  Protected event, style, dx, dy
  
  style = #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget
  dx = 800
  dy = 600
  
  If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, dx, dy, "Main", style)
    
    ; Enable Fullscreen
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS 
      Protected NewCollectionBehaviour
      NewCollectionBehaviour = CocoaMessage(0, WindowID(#Main), "collectionBehavior") | $80
      CocoaMessage(0, WindowID(#Main), "setCollectionBehavior:", NewCollectionBehaviour)
    CompilerEndIf
    
    ; Menu
    CreateMenu(#Menu, WindowID(#Main))
    MenuTitle("Ablage")
    MenuItem(#MenuExitApplication, "Be&enden")
    ; Gadgets
    ListViewGadget(#List, 0, 0, dx, dy)
    
    ; Statusbar
    CreateStatusBar(#Status, WindowID(#Main))
    AddStatusBarField(#PB_Ignore)
    
    UpdateWindow()
    
    Thread1\ThreadID = CreateThread(@thWork(), thread1)
    
    ; Main Loop
    Repeat
      event = WaitWindowEvent()
      Select event
        Case #PB_Event_Menu
          Select EventMenu()
              CompilerIf #PB_Compiler_OS = #PB_OS_MacOS   
              Case #PB_Menu_About
                
              Case #PB_Menu_Preferences
                
              Case #PB_Menu_Quit
                ExitApplication = #True
              CompilerEndIf
              
            Case #MenuExitApplication
              ExitApplication = #True
          EndSelect
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case #List
              
            Case #Edit
              
          EndSelect
          
        Case #PB_Event_SizeWindow
          Select EventWindow()
            Case #Main
              UpdateWindow()
              
          EndSelect
          
        Case #PB_Event_CloseWindow
          Select EventWindow()
            Case #Main
              ExitApplication = #True
              
          EndSelect
          
      EndSelect
      
    Until ExitApplication
    
    ; Warten das der Thread beendet ist
    Thread1\Exit = #True
    Repeat 
      WaitWindowEvent(100)
      If IsThread(Thread1\ThreadID) = 0
        Break
      EndIf
    ForEver
    
  EndIf
  
EndProcedure : Main()

End

[/size]

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 05.12.2018 22:52
von mk-soft
P.S. Wozu ist mein Modul ThreadToGUI

Um Threads beim senden von String nicht zu blockieren, werden für den String immer Speicher angefordert und den Zeiger auf dem String mit PostEvent versendet.
Im Main-Scope, wo WaitWindowEvent(...) aufgerufen wird, wird das gesendete eigene Event verarbeitet und der Speicher für den String wieder freigegeben.

Wird eine Rückantwort im Thread benötigt, werden die Daten mit einem Semaphore versehen und mit PostEvent versendet. In Main-Scope (Aufruf WaitWindowEvent) werden die Daten aufgefüllt und mit dem Semaphore bestätigt das die Daten bereit sind.

P.P.S
Ohne dem Aufruf von WaitWindowEvent(...) werden die Event die mit BindEvent an einer Procedure gebunden werden auch nicht verarbeitet.

Alles was mit GUI zu tun hat muss bei MacOS und Linux im MainScope verarbeitet werden. Warum das so ist kann ich nicht sagen.

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 06.12.2018 00:17
von Programie
mk-soft hat geschrieben:Alles was mit GUI zu tun hat muss bei MacOS und Linux im MainScope verarbeitet werden. Warum das so ist kann ich nicht sagen.
Ist das eine Einschraenkung von PB oder von macOS und Linux?

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 06.12.2018 01:05
von DarkSoul
@ccode_new:
Dass deines immer perfekt synchron ist, ist auch logisch, da du den Sinn und Zweck von Threads perfekt ausgehebelt hast... :mrgreen: :mrgreen:

Ist GetClipboardText() überhaupt eine GUI-Funktion?

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 06.12.2018 01:34
von ccode_new
Naja, wenn die GUI (Fenster, Msg-Box, etc.) und die Clipboard-Funktionen nun mal asynchron laufen, dann ist dein aufgerufener Thread schon fertig, bevor die eigentlichen Funktionen fertig sind.

Diese haben eine eigene Eventschleife zu beachten.

Oder verarbeitest du z.B. bei einer MsgBox das Event beim Klick auf den "OK"-Button in einem Programm selber ?

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 06.12.2018 02:22
von mk-soft
DarkSoul hat geschrieben:@ccode_new:
Ist GetClipboardText() überhaupt eine GUI-Funktion?
Ich weis nur das es mit Threads unter Linux nicht funktioniert und zum Crash führte.
Es war mal eine Anfrage des wegen und habe danach die Verarbeitung vom Clipboard zum Modul ThreadToGUI hinzugefügt.

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 06.12.2018 18:48
von ccode_new
Zur Angabe bei Threads steht bei GTK folgendes:
For thread safety, GDK relies on the thread primitives in GLib, and on the thread-safe GLib main loop.

GLib is completely thread safe (all global data is automatically locked), but individual data structure instances are not automatically locked for performance reasons. So e.g. you must coordinate accesses to the same GHashTable from multiple threads.

GTK+, however, is not thread safe. You should only use GTK+ and GDK from the thread gtk_init() and gtk_main() were called on. This is usually referred to as the “main thread”.

Signals on GTK+ and GDK types, as well as non-signal callbacks, are emitted in the main thread.

You can schedule work in the main thread safely from other threads by using gdk_threads_add_idle() and gdk_threads_add_timeout():

.....

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 06.12.2018 20:08
von Programie
OK, dann verstehe ich das so, dass das keine Einschraenkung von PB ist sondern von GDK/GTK.

Re: GetClipboardText() im Thread fuehrt zu Crash

Verfasst: 06.12.2018 23:25
von mk-soft
So sehe ich das auch und somit macht mein Modul ThreadToGUI sinn 8)