Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Mutex zwischen 2 Prozessen (https://www.delphipraxis.net/198440-mutex-zwischen-2-prozessen.html)

TimWu 2. Nov 2018 11:27

Mutex zwischen 2 Prozessen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Community,

was möchte ich erreichen?:
Die Anwendung soll pro Datenbank-Verbindung nur einmalig geöffnet werden können.

meine Lösungsidee:
Durch das Verwenden von "Mutex" mit Bezeichner (Anwendungsname + Verbindungsinfo) wird überprüft, ob das Programm mit dieser DB-Verbindung bereits läuft.

mein Problem:
Das Mutex verhalten zwischen Prozessen ist sehr merkwürdig.

Ich starte meine Testanwendung (siehe code unten bzw. Anhang) 2 mal.
locken in 1. Anwendung
locken in 2. Anwendung schlägt fehl
unlocken in 1. Anwendung
locken in 1. Anwendung schlägt fehl

Habt ihr eine Idee?

Delphi-Quellcode:
//prozedur zum locken
procedure TForm1.btn1Click(Sender: TObject);
var
 LMutex: THandle;
begin
  LMutex := CreateMutex(nil, True, pCHAR('test'));

  if (LMutex = 0) or (GetLastError <> 0) then
  begin
    MessageDlg(SysErrorMessage(GetLastError), mtInformation, [mbOk], 0);
  end
  else
    FMutex := LMutex;
end;

//prozedur zum unlocken
procedure TForm1.btn2Click(Sender: TObject);
begin
  ReleaseMutex(FMutex);
  CloseHandle(FMutex);
end;

Jasocul 2. Nov 2018 11:45

AW: Mutex zwischen 2 Prozessen
 
CreateMutex erzeugt immer ein neues Handle, wenn die Rechte ausreichen.

Das heißt, wenn du den btn1 drückst, bekommst du jedesmal ein neues Handle, das aber nicht mehr freigegeben wird. Somit hilft es nicht, wenn du btn2 drückst, da das "neue" Handle nicht freigegeben wird.

Es sollte genügen, wenn in btn1 prüfst, ob dein FMutex-Handle bereits existiert und dann gar nicht erst durch die Prozedur läufst.

TimWu 2. Nov 2018 12:08

AW: Mutex zwischen 2 Prozessen
 
Das habe ich schon dadurch abefangen, dass FMutex nur gesetzt wird, wenn es keinen Fehler beim erzeugen gab.

Der besagte Fehler tritt auf, wenn das Mutex in unterschiedlichen Anwendungs-Instanzen erstellt wird.

Jasocul 2. Nov 2018 12:13

AW: Mutex zwischen 2 Prozessen
 
Zitat:

Zitat von TimWu (Beitrag 1417323)
Das habe ich schon dadurch abefangen, dass FMutex nur gesetzt wird, wenn es keinen Fehler beim erzeugen gab.

Nein.
Delphi-Quellcode:
LMutex := CreateMutex(nil, True, pCHAR('test'));
Erzeugt immer ein neues Handle.
Du kannst dsas mit dem Debugger auch leicht prüfen.
Oder, wenn du den Source so änderst, wirst du sehen, dass es das Handle gibt:
Delphi-Quellcode:
  LMutex := CreateMutex(nil, True, pCHAR('test'));

  if (LMutex = 0) or (GetLastError <> 0) then
  begin
    MessageDlg(SysErrorMessage(GetLastError), mtInformation, [mbOk], 0);
    // Durch diesen Code, wird das fehlerhafte Handle wieder freigegeben:
    if LMutex <> 0 then
    begin
      ReleaseMutex(LMutex);
      CloseHandle(LMutex);
    end;
  end
  else
    FMutex := LMutex;

TimWu 2. Nov 2018 12:23

AW: Mutex zwischen 2 Prozessen
 
Natürlich könnte ich ein bestehendes Mutex freigeben, das ist aber nicht meine Absicht.

Ich möchte das Mutex nutzen um zu Prüfen ob das Programm bereits gestartet ist. Wenn ich das Mutex einfach freigebe wiederspräche es seinem Sinn

Kannst du bitte versuchen mein Problem einmal nachzuvollziehen?

Zitat:

locken in 1. Anwendung
locken in 2. Anwendung schlägt fehl
unlocken in 1. Anwendung
locken in 1. Anwendung schlägt fehl

TimWu 2. Nov 2018 12:25

AW: Mutex zwischen 2 Prozessen
 
Zitat:

Zitat von Jasocul (Beitrag 1417319)
CreateMutex erzeugt immer ein neues Handle, wenn die Rechte ausreichen.

Das heißt, wenn du den btn1 drückst, bekommst du jedesmal ein neues Handle, das aber nicht mehr freigegeben wird. Somit hilft es nicht, wenn du btn2 drückst, da das "neue" Handle nicht freigegeben wird.

Es sollte genügen, wenn in btn1 prüfst, ob dein FMutex-Handle bereits existiert und dann gar nicht erst durch die Prozedur läufst.

Es wird doch kein neues Handle erzeugt, wenn ein Fehler auftritt..
wenn das Mutex bereits existiert, wird das Handle des bestehenden Mutex zurückgeliefert

Jasocul 2. Nov 2018 12:31

AW: Mutex zwischen 2 Prozessen
 
Zitat:

Zitat von TimWu (Beitrag 1417327)
Kannst du bitte versuchen mein Problem einmal nachzuvollziehen?

Kannst du bitte versuchen zu verstehen, was ich schreibe? :wink:

Due erzeugst in deiner Prozedur ein neues LOKALES Handle auf das Mutex. Und zwar jedesmal ein weiteres, wenn du den Button drückst. Beim ersten mal weißt du LMutex dem FMutex zu. Alle weiteren CreateMutex werden von dir nicht wieder freigegeben. Und genau das verursacht das von dir beschriebene Problem.

Code:
Es wird doch kein neues Handle erzeugt, wenn ein Fehler auftritt..
wenn das Mutex bereits existiert, wird das Handle des bestehenden Mutex zurückgeliefert
Bitte benutze den Debugger und schaue dir an, was das CreateMutex zurückgibt. Es ist ein neues Handle. Zumindest ist das bei mir so.

Neutral General 2. Nov 2018 12:41

AW: Mutex zwischen 2 Prozessen
 
Zitat:

Zitat von Jasocul (Beitrag 1417330)
Bitte benutze den Debugger und schaue dir an, was das CreateMutex zurückgibt. Es ist ein neues Handle. Zumindest ist das bei mir so.

Zitat:

If the mutex is a named mutex and the object existed before this function call, the return value is a handle to the existing object, GetLastError returns ERROR_ALREADY_EXISTS, bInitialOwner is ignored, and the calling thread is not granted ownership. However, if the caller has limited access rights, the function will fail with ERROR_ACCESS_DENIED and the caller should use the OpenMutex function.
Das Handle ist ein neues, aber das dahinterliegende Mutex ist immer noch das selbe.
1 Mutex - mehrere Handles zu diesem Mutex.

Interessant ist in diesem Fall wahrscheinlich, dass GetLastError ERROR_ALREADY_EXISTS zurückgibt, falls das Mutex schon existiert hat und kein neues erstellt wurde.

Schokohase 2. Nov 2018 12:53

AW: Mutex zwischen 2 Prozessen
 
Hier etwas funktionierendes zum Spielen
Delphi-Quellcode:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Variants, System.Classes, System.SyncObjs,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class( TForm )
    Button1: TButton;
    Button2: TButton;
    procedure Button1_Click( Sender: TObject );
    procedure Button2_Click( Sender: TObject );
  private
    FMutex: TMutex;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  Mutex_Name = {$IFDEF GLOBAL}'global\'+{$ENDIF}'MyMutex';

procedure TForm1.AfterConstruction;
begin
  inherited;
  FMutex := TMutex.Create( nil, false, Mutex_Name );
end;

procedure TForm1.BeforeDestruction;
begin
  FMutex.Free;
  inherited;
end;

procedure TForm1.Button1_Click( Sender: TObject );
begin
  if FMutex.WaitFor( 0 ) = TWaitResult.wrSignaled
  then
    begin
      // We have the mutex
      Button1.Enabled := false;
      Button2.Enabled := True;
    end;
end;

procedure TForm1.Button2_Click( Sender: TObject );
begin
  // We have the mutex, so we release it
  FMutex.Release;
  Button1.Enabled := True;
  Button2.Enabled := false;
end;

end.

Jasocul 2. Nov 2018 12:56

AW: Mutex zwischen 2 Prozessen
 
@Michael:
Ja, du hast Recht. Es ist ein neues Handle auf das selbe Mutex. Dennoch muss das Handle wieder freigegeben werden.

Neutral General 2. Nov 2018 12:57

AW: Mutex zwischen 2 Prozessen
 
Da hast du Recht

Jasocul 2. Nov 2018 13:04

AW: Mutex zwischen 2 Prozessen
 
Vielleicht nochmal eine andere Formulierung:
CreateMutex erzeugt ein Handle auf ein Mutex.
Existiert dieses bereits, wird ein neues Handle darauf erzeugt, allerdings gibt es dann auch ein GetLastError.
Diese neue Handle muss natürlich auch wieder freigegeben werden, da es sonst zu den beschriebenen Problemen führt. Und diese Freigabe fehlt bisher.

TimWu 2. Nov 2018 13:49

AW: Mutex zwischen 2 Prozessen
 
Zitat:

Zitat von Schokohase (Beitrag 1417333)
Hier etwas funktionierendes zum Spielen
...

damit hat es funktioniert.

mir war nicht bewusst, dass ein weiteres Handle den Mutex "sperrt".

Ich danke euch für die schnelle Hilfe :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:08 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz