globaler Mutex / sharedmemory?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

globaler Mutex / sharedmemory?

Beitrag von Toshy »

Hi.
Ich wollte mal wieder etwas mit diesem globlememory / sharedmemory (habe gerade den Namen nicht im Kopf) testen. Das sollte kein so großes PRoblem sein. Ich wollte nur mal wissen ob es eine Möglichkeit gibt ein "globales Mutex" zu erstellen. Also ein Mutex wie in PB nur halt systemweit oder einfach nur so das es für die Programme gilt welche den selben globalen Speicher nutzen.

An sich geht es ja auch, wenn man den dem globalen Speicher gleich Flags zuordnet bzw. die dafür verwendet. Aber dann kann man ja gleich Process-/Thredsichere möglichkeiten nutzen die einem Mutex entsprechen. Ich vermute das dies im Grunde das selbe wäre bei ein selbstgebastelter pBmutex nur halt auf globalem Speicher "geparkt". Vermutlich ASM.
Zwar h atte ich damals einige ASM Codes bei mir mit eingebaut um das damals nochnicht vorhandene Trylockmutex() zu simulieren, da ich ASM aber nicht verstehe wollte und konnte ich damit jetzt nicht rumbasteln.
Vielleicht hat da ja einer schon ne Lösung.

Gruß
Toshy
1. Win10
PB6.1
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Google... http://support.microsoft.com/kb/310153

Code: Alles auswählen


Global g_hMutexAppRunning

Procedure AppInstanceExists()
   
  Protected bAppRunning = FALSE;
  
  ; Create a Global mutex. Use a unique name, For example 
  ; incorporating your company And application name.
  
  g_hMutexAppRunning = CreateMutex_( #Null, #Null, "Global\MyApplication1");
  ; Check If the mutex object already exists, indicating an
  ; existing application instance
  If (g_hMutexAppRunning <> #Null) And (GetLastError_() = #ERROR_ALREADY_EXISTS)
    ; Close the mutex For this application instance. This assumes
    ; the application will inform the user that it is 
    ; about To terminate 
    CloseHandle_( g_hMutexAppRunning );
    g_hMutexAppRunning = #Null;
    ; Return False If a new mutex was created, 
    ; As this means it's the first app instance
  EndIf
  If g_hMutexAppRunning
    ProcedureReturn #False;
  Else
    ProcedureReturn #True
  EndIf

EndProcedure


;- Konstanten

Enumeration
  #Window
EndEnumeration

Enumeration
  #Menu
EndEnumeration

Enumeration
  #Menu_Exit
EndEnumeration

Enumeration
  #StatusBar
EndEnumeration

Enumeration
  #Gadget
EndEnumeration

;- Variablen

Global Exit, WinStyle

Procedure UpdateWindow()

  Protected x, y, dx, dy, menu, status

  menu = MenuHeight()
  status = StatusBarHeight(#StatusBar)
  x = 0
  y = 0
  dx = WindowWidth(#Window)
  dy = WindowHeight(#Window) - menu - status
  ResizeGadget(#Gadget, x, y, dx, dy)
  
EndProcedure

;- Main

If AppInstanceExists()
  MessageRequester("Info", "Programm läuft bereit")
  End
EndIf

WinStyle = #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget

If OpenWindow(#Window, #PB_Ignore, #PB_Ignore, 800, 500, "Window", WinStyle)

  If CreateMenu(#Menu, WindowID(#Window))
    MenuTitle("&Datei")
    MenuItem(#Menu_Exit, "Be&enden")
  EndIf
  
  If CreateStatusBar(#StatusBar, WindowID(#Window))
    
  EndIf
  
  If CreateGadgetList(WindowID(#Window))
    ListViewGadget(#Gadget, 0,0,0,0)
  EndIf
  
  exit = 0
  
  Repeat
    event = WaitWindowEvent()
    Select event
    
    Case #PB_Event_Menu
      Select EventMenu()
        Case #Menu_Exit
          exit = 1
      EndSelect
      
    Case #PB_Event_SizeWindow
      UpdateWindow()
      
    Case #PB_Event_CloseWindow
      exit = 1
      
    EndSelect
    
  Until exit
EndIf

; !!! NICHT VERGESSEN !!! - Global Mutex wieder freigeben
CloseHandle_(g_hMutexAppRunning)
FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Danke erstmal.
Ich habe hier am Rechner gerade kein PB installiert (nicht zu Hause) kann daher nicht testen. Allerdings hab ich mich wohl nicht genau genug ausgedrückt. Ich habe nicht vor dafür zu sorgen daß nur eine Programminstance läuft, sondern im Grunde das selbe Lock-, Trylock- und Unlockmutex wie in PB auf "Überprocessbasis" zu nutzen.
Also wirklich das ein Mutex erstellt wird bzw. ein (ASM?-)Flag und dann alle aufrufenden Threads und Processe stehen bleiben bzw. weiterlaufen mit melden. Besonders problematsich könnte sein, daß man zwar in seinem einzelnen Programm noch schauen kann ob der Mutex existiert ohne einen schweren Fehler auszulösen (auf Grund der Codestruktur) aber processübergreifend es ja passieren könnte das ein anderer Process das Mutex löscht.
Beim erstellen wäre dein code ja noch ok, aber rauszubekommen welche Processinstance die letzte ist..., ja das ist sicher ein Problem.

!!!: Ich werde mir den Code aber am Wochenende und die Funktion mal genauer anschauen. Mal sehn wie die sich bei Instancen verhält.

Natürlich sollte es wenn möglich betriebssystemübergreifend sein oder wenigstens auf den anderen Systemen später auch eine Möglichkeit geben. Ich erstelle gerade Routinen die später auch gleich auf Linux laufen sollten, selbst wenn ich Linux noch nicht wirklich kenne oder habe.

Gruß
Toshy
1. Win10
PB6.1
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Eine alternative wäre nicht mit shared memory zu arbeiten, sondern mit Pipes. Habe ein Beispiel. Müsste aber noch ausgearbeitet werden.

Code: Alles auswählen

;-TOP
; Kommentar     : Multithreaded Pipe Server (Übersetzt aus MSDN)
; Author        : mk-soft
; Second Author : 
; Datei         : PipeServer.pb
; Version       : 1.01
; Erstellt      : 10.02.2007
; Geändert      : 28.03.2009
; 
; Compilermode  :
;
; ***************************************************************************************

#BUFSIZE = 4096
 
Declare InstanceThread(lpvParam.l); 
Declare GetAnswerToRequest(chRequest.s, *chReply.s, *pchBytes.l); 
 
Procedure main() 

   Protected fConnected.l ; BOOL
   Protected dwThreadId.l ; DWORD 
   Protected hPipe.l, hThread.l ; HANDLE 
   Protected lpszPipename.s = "\\.\pipe\mynamedpipe" ; LPTSTR 
 
;// The main loop creates an instance of the named pipe And 
;// then waits For a client To connect To it. When the client 
;// connects, a thread is created To handle communications 
;// With that client, And the loop is repeated. 
 
   Repeat 
   ;{ 
      Debug "Create Pipe"
      hPipe = CreateNamedPipe_(lpszPipename, #PIPE_ACCESS_DUPLEX, #PIPE_TYPE_MESSAGE | #PIPE_READMODE_MESSAGE | #PIPE_WAIT, #PIPE_UNLIMITED_INSTANCES, #BUFSIZE, #BUFSIZE, 0, #Null)

      If (hPipe = #INVALID_HANDLE_VALUE) 
      ;{
          Debug ("CreatePipe failed")
          ProcedureReturn 0
      ;}
      EndIf
      ;// Wait For the client To connect; if it succeeds, 
      ;// the function returns a nonzero value. If the function returns 
      ;// zero, GetLastError returns ERROR_PIPE_CONNECTED. 
      Debug "Wait for Connect"
      fConnected = ConnectNamedPipe_(hPipe, #Null) 
      
      ; ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); 
      If fConnected = 0
        If GetLastError_() = #ERROR_PIPE_CONNECTED
          fConnected = #True
        EndIf
      EndIf
      
      If fConnected
      ;{ 
      ;// Create a thread For this client. 
         Debug "Connect Client"
         Debug "hPipe: " +Str(hPipe)
         ;hThread = CreateThread(@InstanceThread(), hPipe)
         hThread = CreateThread_(#Null, 0, @InstanceThread(), hPipe, 0, @dwThreadId)

          If (hThread = #Null) 
         ;{
            Debug ("CreateThread failed"); 
            ProcedureReturn 0;
         ;}
         Else
          Debug "Create Thread Ok"
         EndIf
      ;} 
      Else 
        ;// The client could Not connect, so close the pipe. 
         CloseHandle_(hPipe); 
      EndIf
   ;}
   ForEver
     
   ProcedureReturn 1;
    
EndProcedure 
 
 
Procedure InstanceThread(lpvParam.l) 
;{ 
   Protected chRequest.s{#BUFSIZE}; CHAR 
   Protected chReply.s{#BUFSIZE}; CHAR
   Protected cbBytesRead.l, cbReplyBytes.l, cbWritten.l; DWORD
   Protected fSuccess.l; BOOL
   Protected hPipe; HANDLE
 
;// The thread's parameter is a handle to a pipe instance. 
 
   hPipe = lpvParam; 
   While (1) 
   ;{ 
   ;// Read client requests from the pipe. 
      fSuccess = ReadFile_(hPipe, @chRequest, #BUFSIZE, @cbBytesRead, #Null)

      If (fSuccess = 0); | (cbBytesRead = 0) 
         Break; 
      EndIf
      
      chReply = "Echo: " + chRequest
      cbReplyBytes = Len(chReply) 
   ;// Write the reply To the pipe. 
      fSuccess = WriteFile_(hPipe, @chReply, cbReplyBytes, @cbWritten, #Null)

      If (fSuccess = 0) | (cbReplyBytes <> cbWritten) 
        Break; 
      EndIf
  ;}
  Wend 
 
;// Flush the pipe To allow the client To Read the pipe's contents 
;// before disconnecting. Then disconnect the pipe, And close the 
;// handle To this pipe instance. 
 
   FlushFileBuffers_(hPipe); 
   DisconnectNamedPipe_(hPipe); 
   CloseHandle_(hPipe); 
;}
EndProcedure


;- Main
Main()

Code: Alles auswählen

; Test PipeServer

Procedure.s FormatMessage(ErrorNumber.l)

  Protected len
  
  len = FormatMessage_(#FORMAT_MESSAGE_ALLOCATE_BUFFER|#FORMAT_MESSAGE_FROM_SYSTEM,0,ErrorNumber,0,@Buffer,0,0)
  If len
    ProcedureReturn PeekS(Buffer, len - 2)
    LocalFree_(Buffer)
  Else
    ProcedureReturn "Errorcode: " + Hex(ErrorNumber)
  EndIf
  
EndProcedure



Pipe.s = "\\.\pipe\mynamedpipe"

send.s = "Hallo Welt"
recv.s = Space(1000)

If CallNamedPipe_(@Pipe, send, Len(send) + 1, recv, 1000, @cb, 1000)
  Debug recv
Else
  Debug FormatMessage(GetLastError_())
EndIf
FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten