Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Multithreading (Access Violation) (https://www.delphipraxis.net/190911-multithreading-access-violation.html)

exchange 18. Nov 2016 15:48

Multithreading (Access Violation)
 
Hallo,
ich bin gerade dabei meine erste Multithreading Anwendung am basteln.
Es sollen, aktuell, 2 Threads Datensätze aus einer DB holen und diese dann via http hochladen.

Ich hatte mich für die Komponente BMDThread entschieden. Wenn man mal die Datenbankverbindung außen vor lässt, funktioniert das ganze auch gut :)

Beide Threads werden gleichzeitig gestartet. Dabei erhalte ich entweder eine Access Violation, "Zu wenig Arbeitsspeicher" oder es funktioniert mal.

Wenn ich die Threads zeitversetzt starte, funktioniert es einwandfrei.

Im Execute Event der Threads habe ich die procedure drin stehen z.B. ExecuteAccept();

Hier die gesamte procedure:
Delphi-Quellcode:
procedure TForm_Main.ExecuteAccept();
var DBConnection: TUniConnection; DBQuery: TUniQuery;
begin
  DBConnection:=TUniConnection.Create(nil);
  DBConnection.Server:='localhost';
  DBConnection.Port:=3306;
  DBConnection.Username:='root_copy';
  DBConnection.Password:='password';
  DBConnection.ProviderName:='MySQL';

  try
    DBConnection.Connect;
  except
    on E : Exception do
    begin
      cxMemo_Accept.Lines.Add('DBVerbindung Fehler');
      cxMemo_Accept.Lines.Add('Exception message = '+E.Message);
    end;
  end;

  if DBConnection.Connected then
  begin
    try
      DBQuery:=TUniQuery.Create(nil);
      DBQuery.Connection:=DBConnection;
      DBQuery.SQL.Text:='SELECT * FROM TABELLE h LIMIT 100;';
      DBQuery.Active:=true;
      cxMemo_Accept.Lines.Add(inttostr(DBQuery.RecordCount));
      DBQuery.Active:=false;
      DBQuery.Free;
    except
    on E : Exception do
    begin
      cxMemo_Accept.Lines.Add('Query Fehler');
      cxMemo_Accept.Lines.Add('Exception message = '+E.Message);
    end;
    end;
    DBConnection.Close;
  end;

  DBConnection.Free;
end;
Ich verstehe nicht genau wo das Problem ist. Habe doch extra alles in den jeweiligen Thread gepackt. Die zweite Procudure ist exakt gleich (die SQL Abfrage ist anders).

Vielleicht kann sich das einer erklären und mir auf die Sprünge helfen. Alternativ wollte ich die SQL Verbindung auf das Main Form setzen aber davon wird in mehreren Beiträgen abgeraten.



Vielen Dank

Aviator 18. Nov 2016 15:55

AW: Multithreading (Access Violation)
 
Aus einem Thread heraus solltest du schonmal nicht auf die GUI zugreifen. Des Weiteren brauchst du für jeden Thread eine eigene Connection. Sonst wird das wohl beim Ausführen deiner Statements Probleme geben.

HolgerX 18. Nov 2016 17:41

AW: Multithreading (Access Violation)
 
Hmm..

und wenn die verwendeten Komponenten mit COM arbeiten, braucht jeder Thread im Execute:

Delphi-Quellcode:
  CoInitializeEX(nil,COINIT_APARTMENTTHREADED);
  try

    ... Datenbankaktionen

  finally
    CoUninitialize;
  end;

exchange 18. Nov 2016 18:02

AW: Multithreading (Access Violation)
 
Hallo,
Danke für die Antworten. Ich habe zwei Thread Elemente auf dem Form liegen. Somit auch 2x execute. Vorher hatte ich den obigen Code innerhalb des executes 1:1.

Damit hatten auch beide Threads eine eigene Connnection. Der Fehler kommt beim Verbindungsaufbau im ersten try except Block.


MfG

Delphi-Laie 20. Nov 2016 21:27

AW: Multithreading (Access Violation)
 
Zeig doch mal Deinen gesamten Quelltext! So ist es doch nur ein Rätseln.

hoika 21. Nov 2016 01:50

AW: Multithreading (Access Violation)
 
Hallo,
wo ist das Synchronize beim Zugriff das das Memo?

exchange 21. Nov 2016 08:09

AW: Multithreading (Access Violation)
 
Hallo,
danke für die Infos. Hat aber leider nichts gebracht. Der Fehler entsteht wenn ich die Verbindung aufbauen will.

Folgende Fehler erscheinen:
Zugriffsverletzung bei Adresse 008BC0B5 in Modul 'ServiceTool.exe'. Lesen von Adresse 0000000C
ODER
DBVerbindung Fehler
Exception message = Zu wenig Arbeitsspeicher

Ohne das ich Parameter ändere, sind die Fehler nur manchmal. Sobald ich hingehe und die Threads zeitversetzt starte (z.B. 500 ms) erhalte ich keine Fehler.

Anbei mal den gesamten Quellcode von dem Beispiel.

Delphi-Quellcode:
unit main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, BMDThread, cxGraphics, cxLookAndFeels,
  cxLookAndFeelPainters, Vcl.Menus, dxSkinsCore, dxSkinBlack, dxSkinBlue,
  dxSkinBlueprint, dxSkinCaramel, dxSkinCoffee, dxSkinDarkRoom, dxSkinDarkSide,
  dxSkinDevExpressDarkStyle, dxSkinDevExpressStyle, dxSkinFoggy,
  dxSkinGlassOceans, dxSkinHighContrast, dxSkiniMaginary, dxSkinLilian,
  dxSkinLiquidSky, dxSkinLondonLiquidSky, dxSkinMcSkin, dxSkinMetropolis,
  dxSkinMetropolisDark, dxSkinMoneyTwins, dxSkinOffice2007Black,
  dxSkinOffice2007Blue, dxSkinOffice2007Green, dxSkinOffice2007Pink,
  dxSkinOffice2007Silver, dxSkinOffice2010Black, dxSkinOffice2010Blue,
  dxSkinOffice2010Silver, dxSkinOffice2013DarkGray, dxSkinOffice2013LightGray,
  dxSkinOffice2013White, dxSkinOffice2016Colorful, dxSkinOffice2016Dark,
  dxSkinPumpkin, dxSkinSeven, dxSkinSevenClassic, dxSkinSharp, dxSkinSharpPlus,
  dxSkinSilver, dxSkinSpringTime, dxSkinStardust, dxSkinSummer2008,
  dxSkinTheAsphaltWorld, dxSkinsDefaultPainters, dxSkinValentine,
  dxSkinVisualStudio2013Blue, dxSkinVisualStudio2013Dark,
  dxSkinVisualStudio2013Light, dxSkinVS2010, dxSkinWhiteprint,
  dxSkinXmas2008Blue, Vcl.StdCtrls, cxButtons, Vcl.ExtCtrls, cxControls,
  cxContainer, cxEdit, cxTextEdit, cxMemo, cxLabel, Uni, MySQLUniProvider,
  IdBaseComponent, IdThreadComponent, Data.DB, DBAccess;

type
  TForm_Main = class(TForm)
    cxButton1: TcxButton;
    Timer_Export_Radius_Accept: TTimer;
    Timer_Export_Radius_Deny: TTimer;
    cxMemo_Accept: TcxMemo;
    cxLabel1: TcxLabel;
    cxMemo_Deny: TcxMemo;
    cxLabel2: TcxLabel;
    idThread_Export_Radius_Accept: TIdThreadComponent;
    idThread_Export_Radius_Deny: TIdThreadComponent;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Timer_Export_Radius_AcceptTimer(Sender: TObject);
    procedure Timer_Export_Radius_DenyTimer(Sender: TObject);
    procedure Thread_Export_Radius_DenyTerminate(Sender: TObject;
      Thread: TBMDExecuteThread; var Data: Pointer);
    procedure Thread_Export_Radius_AcceptStart(Sender: TObject;
      Thread: TBMDExecuteThread; var Data: Pointer);
    procedure Thread_Export_Radius_DenyStart(Sender: TObject;
      Thread: TBMDExecuteThread; var Data: Pointer);
    procedure cxButton1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure idThread_Export_Radius_DenyRun(Sender: TIdThreadComponent);
    procedure idThread_Export_Radius_AcceptRun(Sender: TIdThreadComponent);
    procedure idThread_Export_Radius_AcceptTerminate(
      Sender: TIdThreadComponent);
    procedure idThread_Export_Radius_DenyTerminate(Sender: TIdThreadComponent);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form_Main: TForm_Main;
  MySQL: TMySQLUniProvider;

implementation

{$R *.dfm}

procedure TForm_Main.idThread_Export_Radius_AcceptRun(
  Sender: TIdThreadComponent);
var DBConnection: TUniConnection; DBQuery: TUniQuery;
begin
  cxMemo_Accept.Lines.Add(FormatDateTime('dd.mm.yyyy, hh:nn:ss', now) + ', Thread gestartet');

  DBConnection:=TUniConnection.Create(nil);
  DBConnection.Server:='172.16.6.50';
  DBConnection.Port:=3306;
  DBConnection.Username:='root_copy';
  DBConnection.Password:='password';
  DBConnection.ProviderName:='MySQL';
  DBConnection.Database:='xxx';
  DBConnection.LoginPrompt:=false;
  DBConnection.Pooling:=true;

  try
    DBConnection.Connect;
  except
    on E : Exception do
    begin
      cxMemo_Accept.Lines.Add('DBVerbindung Fehler');
      cxMemo_Accept.Lines.Add('Exception message = '+E.Message);
    end;
  end;

  if DBConnection.Connected then
  begin
    try
      DBQuery:=TUniQuery.Create(nil);
      DBQuery.Connection:=DBConnection;
      DBQuery.SQL.Text:='SELECT * FROM hotspotstatistik h LIMIT 100;';
      DBQuery.Active:=true;
      cxMemo_Accept.Lines.Add(inttostr(DBQuery.RecordCount));
      DBQuery.Active:=false;
      DBQuery.Free;
    except
    on E : Exception do
    begin
      cxMemo_Accept.Lines.Add('Query Fehler');
      cxMemo_Accept.Lines.Add('Exception message = '+E.Message);
    end;
    end;
    DBConnection.Close;
  end;

  DBConnection.Free;

  Sender.Stop;
end;

procedure TForm_Main.idThread_Export_Radius_AcceptTerminate(
  Sender: TIdThreadComponent);
begin
  cxMemo_Accept.Lines.Add(FormatDateTime('dd.mm.yyyy, hh:nn:ss', now) + ', Thread beendet');
  Timer_Export_Radius_Accept.Enabled:=true;
end;

procedure TForm_Main.Thread_Export_Radius_AcceptStart(Sender: TObject;
  Thread: TBMDExecuteThread; var Data: Pointer);
begin
  cxMemo_Accept.Lines.Add('Thread Start');
end;

procedure TForm_Main.Thread_Export_Radius_DenyStart(Sender: TObject;
  Thread: TBMDExecuteThread; var Data: Pointer);
begin
  cxMemo_Deny.Lines.Add('Thread Start');
end;

procedure TForm_Main.Thread_Export_Radius_DenyTerminate(Sender: TObject;
  Thread: TBMDExecuteThread; var Data: Pointer);
begin
  cxMemo_Deny.Lines.Add('Thread Ende');
  Timer_Export_Radius_Deny.Enabled:=true;
end;

procedure TForm_Main.Timer_Export_Radius_AcceptTimer(Sender: TObject);
begin
  Timer_Export_Radius_Accept.Enabled:=false;
  idThread_Export_Radius_Accept.Start();
end;

procedure TForm_Main.Timer_Export_Radius_DenyTimer(Sender: TObject);
begin
  Timer_Export_Radius_Deny.Enabled:=false;
  idThread_Export_Radius_Deny.Start();
end;

procedure TForm_Main.cxButton1Click(Sender: TObject);
begin
  cxButton1.Enabled:=false;
  Timer_Export_Radius_Accept.Enabled:=true;
  Timer_Export_Radius_Deny.Enabled:=true;
end;

procedure TForm_Main.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  idThread_Export_Radius_Accept.OnTerminate := NIL;
  idThread_Export_Radius_Accept.Stop();

  idThread_Export_Radius_Deny.OnTerminate := NIL;
  idThread_Export_Radius_Deny.Stop();

  MySQL.Free;
end;

procedure TForm_Main.FormCreate(Sender: TObject);
begin
  MySQL:=TMySQLUniProvider.Create(nil);
end;

procedure TForm_Main.idThread_Export_Radius_DenyRun(Sender: TIdThreadComponent);
var DBConnection: TUniConnection; DBQuery: TUniQuery;
begin
  cxMemo_Deny.Lines.Add(FormatDateTime('dd.mm.yyyy, hh:nn:ss', now) + ', Thread gestartet');
  DBConnection:=TUniConnection.Create(nil);
  DBConnection.Server:='172.16.6.50';
  DBConnection.Port:=3306;
  DBConnection.Username:='root_copy';
  DBConnection.Password:='password';
  DBConnection.Database:='xxx';
  DBConnection.ProviderName:='MySQL';
  DBConnection.LoginPrompt:=false;
  DBConnection.Pooling:=true;

  try
    DBConnection.Connect;
  except
    on E : Exception do
    begin
      cxMemo_Deny.Lines.Add('DBVerbindung Fehler');
      cxMemo_Deny.Lines.Add('Exception message = '+E.Message);
    end;
  end;

  if DBConnection.Connected then
  begin
    try
      DBQuery:=TUniQuery.Create(nil);
      DBQuery.Connection:=DBConnection;
      DBQuery.SQL.Text:='SELECT * FROM hotspotstatistik h LIMIT 100;';
      DBQuery.Active:=true;
      cxMemo_Deny.Lines.Add(inttostr(DBQuery.RecordCount));
      DBQuery.Active:=false;
      DBQuery.Free;
    except
    on E : Exception do
    begin
      cxMemo_Deny.Lines.Add('Query Fehler');
      cxMemo_Deny.Lines.Add('Exception message = '+E.Message);
    end;
    end;
    DBConnection.Close;
  end;

  DBConnection.Free;
  Sender.Stop;
end;

procedure TForm_Main.idThread_Export_Radius_DenyTerminate(
  Sender: TIdThreadComponent);
begin
  cxMemo_Deny.Lines.Add(FormatDateTime('dd.mm.yyyy, hh:nn:ss', now) + ', Thread beendet');
  Timer_Export_Radius_Deny.Enabled:=true;
end;

end.

MFG

jaenicke 21. Nov 2016 08:16

AW: Multithreading (Access Violation)
 
Wie schon zweimal geschrieben wurde:
Du greifst aus deinem Thread unsynchronisiert (sprich im Kontext des Threads) auf dein Memo zu. Das kann nicht funktionieren! Es wird so immer solche nicht richtig greifbaren Probleme geben wie du sie jetzt hast.

Du zerschießt dir so den Speicher und die Folgen sieht man an ganz anderer Stelle.

Du darfst immer nur im Kontext des Hauptthreads auf visuelle Komponenten zugreifen. Wenn du über Datei --> Neu ein Threadobjekt erstellst, steht das dort auch direkt als Warnung im Kommentar drin.

Sherlock 21. Nov 2016 08:20

AW: Multithreading (Access Violation)
 
Schmeiß mal die Indys da raus. Das hat mit Multithreading nicht so viel zu tun, wie Du glaubst.
Welche Delphi-Version hast du? Evntuell wäre ein TParallel.For etwas für Dich. Falls Du ein älteres Delphi hast, dann geht es auch über das klassische Threading per Threadklasse deklarieren und im Code an der gewünschten Stelle ausführen.
DEtails hier: http://www.delphipraxis.net/9238-thr...it-delphi.html

Sherlock

exchange 21. Nov 2016 09:55

AW: Multithreading (Access Violation)
 
Hallo,
vielen Dank für eure Hilfe.
Auf die Memos habe ich auch damals getippt aber die waren es nicht. Habe diese dann drin stehen gelassen. Habe nun eine neue Anwendung gebaut. Erhalte dort aber den gleichen Fehler:

Macht keine Probleme:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  sleep(1000);
  Thread1.Resume;
  sleep(1000);
  Thread2.Resume;
end;

Macht Probleme:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Thread1.Resume;
  Thread2.Resume;
end;
Darf man einen Thread nicht nacheinander ausführen? Einzelnd funktionieren die Threads auch. Ich habe schon das Forum bei Devart durchsucht, da ich das Problem hier sehe: DBConnection:=TUniConnection.Create(nil);

Kompletter Quellcode:
Delphi-Quellcode:
unit main;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  TThread1 = class(TThread)
    protected
    procedure Execute; override;
  end;

  TThread2 = class(TThread)
    protected
    procedure Execute; override;
  end;

var
  Form1: TForm1;
  MySQL: TMySQLUniProvider;
  Thread1: TThread1;
  Thread2: TThread2;

implementation

{$R *.dfm}

procedure TThread1.Execute;
var DBConnection: TUniConnection; DBQuery: TUniQuery;
begin
  while not Terminated do
  begin
    DBConnection:=TUniConnection.Create(nil);
    DBConnection.Server:='172.16.6.50';
    DBConnection.Port:=3306;
    DBConnection.Username:='root_copy';
    DBConnection.Password:='password';
    DBConnection.ProviderName:='MySQL';
    DBConnection.Database:='testdb';

    DBConnection.Connect;

    if DBConnection.Connected then
    begin
        DBQuery:=TUniQuery.Create(nil);
        DBQuery.Connection:=DBConnection;
        DBQuery.SQL.Text:='INSERT into test SET datum=NOW(), thread=1;';
        DBQuery.Execute;
        DBQuery.Free;
      DBConnection.Close;
    end;

    DBConnection.Free;

    sleep(2000);
  end;
end;

procedure TThread2.Execute;
var DBConnection: TUniConnection; DBQuery: TUniQuery;
begin
  while not Terminated do
  begin
  DBConnection:=TUniConnection.Create(nil);
    DBConnection.Server:='172.16.6.50';
    DBConnection.Port:=3306;
    DBConnection.Username:='root_copy';
    DBConnection.Password:='password';
    DBConnection.Database:='testdb';
    DBConnection.ProviderName:='MySQL';

    DBConnection.Connect;

    if DBConnection.Connected then
    begin
        DBQuery:=TUniQuery.Create(nil);
        DBQuery.Connection:=DBConnection;
        DBQuery.SQL.Text:='INSERT into test SET datum=NOW(), thread=2;';
        DBQuery.Execute;
        DBQuery.Free;
      DBConnection.Close;
    end;

    DBConnection.Free;

    sleep(2000);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  sleep(1000);
  Thread1.Resume;
  sleep(1000);
  Thread2.Resume;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  MySQL.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MySQL:=TMySQLUniProvider.Create(nil);

  Thread1 := TThread1.Create(True);
  Thread1.FreeOnTerminate := True;

  Thread2 := TThread2.Create(True);
  Thread2.FreeOnTerminate := True;
end;

end.

MFG

taveuni 21. Nov 2016 10:18

AW: Multithreading (Access Violation)
 
Du erstellst im Execute X-Connections und Querys mit der gleichen Variable.

Delphi-Quellcode:
  while not Terminated do
  begin
und gibst sie beim ersten erfolgreichen wieder frei. Die anderen gucken dann in die Röhre

exchange 21. Nov 2016 11:05

AW: Multithreading (Access Violation)
 
Hallo,
meiner Meinung nach ist das egal, da ich alles wieder freigebe was ich vorher generiert habe.

Aber gut. Zum Testen while Schleife entfernt, sodass jeder Thread einmalig durchläuft.

Fehler bleibt.

p80286 21. Nov 2016 11:29

AW: Multithreading (Access Violation)
 
Auf den ersten Blick erscheint mir der Code des zweiten Beispiels ganz in Ordnung, nur der Sinn des
Delphi-Quellcode:
while not terminated
erschließt sich mir nicht ganz.

Wie wäre es wenn Du den Code mit ein paar exeptions aufhübschen würdest um den Fehler etwas einzugrenzen?

Gruß
K-H

stahli 21. Nov 2016 11:36

AW: Multithreading (Access Violation)
 
Zitat:

Zitat von exchange (Beitrag 1354254)
Darf man einen Thread nicht nacheinander ausführen? Einzelnd funktionieren die Threads auch.

Stell Dir vor, Du hast einen Thread, der 5 mal I := I + 1 ausführt und einen zweiten, der 5 mal I := I - 1 ausführt. Beide Threads brauchen ca. 1/2 Sekunde dafür.

Wenn Du Thread 1 startest , eine Sekunde wartest und Thread 2 ausführst, ist I wie vor den Threads 0.

Wenn Du beide Threads unmittelbar nacheinander ausführst, sollte eigentlich ja auch 0 rauskommen. Tut es aber nicht zwangsläufig.

"I := I + 1;" wird in mehreren CPU-Zyklen ausgeführt:

Merke Wert von I
Merke 1
Addiere beide Zahlen
Schreibe Ergebnis in I

Analog wird für Thread 2 folgendes getan:

Merke Wert von I
Merke 1
Subtrahiere Zahl2 von Zahl1
Schreibe Ergebnis in I

Wenn beide Threads gleichzeitig laufen bestimmt Windows, wann welcher Thread Arbeitszeit bekommen soll. Dazu wird z.B. Thread1 unterbrochen und Thread2 bekommt Arbeitszeit.

Dann passiert u.U. folgendes:

(Thread1)
Merke Wert von I
Merke 1
Addiere beide Zahlen
-->(Thread2)
Merke Wert von I
Merke 1
Subtrahiere Zahl2 von Zahl1
Schreibe Ergebnis in I
<--(weiter in Thread1)
Schreibe Ergebnis in I

Die Arbeit von Thread2 wird somit im Ergebnis nicht berücksichtigt.
Als Ergebnis kann alles zwischen -5 bis +5 raus kommen.


Wenn nicht nur einfache Integervariablen geteilt werden kann es zu weitaus schwerwiegenderen Fehlern bis hin zu kompletten Abstürzen kommen.

Man muss also darauf achten, dass gemeinsame Ressourcen gegen kritische gemeinsame Zugriffe abgesichert werden.


[EDIT] Das nur als grundsätzliche Anmerkung. Ob im genannten Beispiel so ein Problem vorliegen kann, kann ich nicht beurteilen.

Der schöne Günther 21. Nov 2016 11:42

AW: Multithreading (Access Violation)
 
Ich habe das Thema nur überflogen da ich zu UniDac nichts sagen kann.

Aber:
- Beide Threads haben doch überhaupt keine (offensichtlich) gemeinsam verwendeten Resourcen, alles ok
- Das "Thread.Create(False)", "While not Terminated" und "Resume" sind auch völlig legitim

- Wir wissen nur dass eine AV auftritt, nicht aber, welche Zeile der Debugger anmeckert


Vielleicht habe ich zu schlampig überflogen, aber der Code an sich ist doch korrekt, wenn man davon ausgeht dass die verwendete "UniDac"-Library das auch zulässt und nicht fordert, nur im Hauptthread ausgeführt zu werden.

Da einem alles um die Ohren fliegt ist die Annahme wohl nicht korrekt. Oder was übersehe ich?

Zacherl 21. Nov 2016 12:09

AW: Multithreading (Access Violation)
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1354277)
aber der Code an sich ist doch korrekt, wenn man davon ausgeht dass die verwendete "UniDac"-Library das auch zulässt und nicht fordert, nur im Hauptthread ausgeführt zu werden.

Da einem alles um die Ohren fliegt ist die Annahme wohl nicht korrekt. Oder was übersehe ich?

Sehe ich genauso :thumb:

Da nur eine einzige globale Instanz der
Delphi-Quellcode:
TMySQLUniProvider
Klasse erstellt wird, kann ich mir gut vorstellen, dass es hier kracht, wenn diese nicht thread-safe ist und die in den Threads erstellten Klassen da irgendwie indirekt drauf zugreifen.

taveuni 21. Nov 2016 12:25

AW: Multithreading (Access Violation)
 
Zitat:

Zitat von exchange (Beitrag 1354271)
Zum Testen while Schleife entfernt, sodass jeder Thread einmalig durchläuft.

Fehler bleibt.

Und welcher?

Ich verwende die Devart MySql und MSSql Libraries. Vermutich werden die Unidac ähnlich sein. Du kannst im Hauptthread eine Verbindung statisch oder dynamisch erzeugen. Dann diese in allen Threads Assignen. Dies nur als Info damit Du im Thread nicht jedesmal die Verbindungsdaten mitführen musst.

Delphi-Quellcode:

var
  Qry: TMSQuery;
  Conn: TMSConnection;
begin
  Conn:= TMSConnection.Create(Nil);
  Conn.Assign(FMyGlobalMsConnection);
  Qry:= TMSQuery.Create(Nil);
  Qry.Connection:= Conn;
  Try
    Try

    except
      on E: Exception do LogException(e, 'MyException');
    end;
  Finally
    Qry.Free;
    Conn.Free;
  End;

p80286 21. Nov 2016 15:16

AW: Multithreading (Access Violation)
 
Zitat:

Zitat von Zacherl (Beitrag 1354286)
Da nur eine einzige globale Instanz der
Delphi-Quellcode:
TMySQLUniProvider
Klasse erstellt wird, kann ich mir gut vorstellen, dass es hier kracht, wenn diese nicht thread-safe ist und die in den Threads erstellten Klassen da irgendwie indirekt drauf zugreifen.

Hab ich da was übersehen? In dem Zweiten Sourcecode hat jeder Thread eine eigene Connection und eine eigene Query?
Zitat:

Delphi-Quellcode:
procedure TThread1.Execute;
var DBConnection: TUniConnection; DBQuery: TUniQuery;
begin
   while not Terminated do
   begin
     DBConnection:=TUniConnection.Create(nil);
     DBConnection.Server:='172.16.6.50';
     DBConnection.Port:=3306;
     DBConnection.Username:='root_copy';
     DBConnection.Password:='password';
     DBConnection.ProviderName:='MySQL';
     DBConnection.Database:='testdb';

     DBConnection.Connect;

     if DBConnection.Connected then
     begin
         DBQuery:=TUniQuery.Create(nil);
         DBQuery.Connection:=DBConnection;
         DBQuery.SQL.Text:='INSERT into test SET datum=NOW(), thread=1;';
         DBQuery.Execute;
         DBQuery.Free;
       DBConnection.Close;
     end;

     DBConnection.Free;

     sleep(2000);
   end;
end;

Gruß
K-H

himitsu 21. Nov 2016 16:37

AW: Multithreading (Access Violation)
 
Zitat:

Zitat von p80286 (Beitrag 1354305)
Hab ich da was übersehen? In dem Zweiten Sourcecode hat jeder Thread eine eigene Connection und eine eigene Query?

Die Aussage bezog sich auf den Provider.
Delphi-Quellcode:
MySQL:=TMySQLUniProvider.Create(nil);

taveuni 21. Nov 2016 16:41

AW: Multithreading (Access Violation)
 
Aber das Ding wird in den Threads ja gar nicht benutzt? Oder habe ich Tomaten auf den Augen? Wofür ist das überhaupt?

Zacherl 21. Nov 2016 16:43

AW: Multithreading (Access Violation)
 
Zitat:

Zitat von taveuni (Beitrag 1354316)
Aber das Ding wird in den Threads ja gar nicht benutzt? Oder habe ich Tomaten auf den Augen? Wofür ist das überhaupt?

Du setzt ja den Provider als String-Property. Ich nehme mal an, dass spätestens in der
Delphi-Quellcode:
TUniConnection.Connect()
Methode nach der globalen Provider Instanz anhand dieses Strings gesucht wird.

jaenicke 21. Nov 2016 20:05

AW: Multithreading (Access Violation)
 
Bei AnyDAC/FireDAC muss man Multithreading explizit aktivieren. Vielleicht muss man das dort auch?

exchange 22. Nov 2016 12:24

AW: Multithreading (Access Violation)
 
Hallo Leute,
vielen Dank für die zahlreichen Antworten.

Ich wusste nicht, dass man die Verbindung Assignen kann. Habe das eben mal testweise gemacht aber bringt leider auch einen access Fehler. Laut Hersteller ist die Komponente Multithread sicher.
Habe auch gesucht ob es einen "Schalter" für Multi Threading gibt und dort das Forum durchsucht aber nichts gefunden. Ich werde parallel nun dort man einen Beitrag schreiben, da ich der Meinung bin, dass es an deren Komponente liegt.

Habe auch mal MySQL:= TMySQLUniProvider.Create(nil); in den Thread reingezogen. Brachte leider auch nichts.

Sobald ich mehr Infos habe, würde ich den Beitrag aus deren Forum verlinken.

Vielen Dank

MFG

Zacherl 22. Nov 2016 16:32

AW: Multithreading (Access Violation)
 
Zitat:

Zitat von exchange (Beitrag 1354382)
Habe auch mal MySQL:= TMySQLUniProvider.Create(nil); in den Thread reingezogen. Brachte leider auch nichts.

Zieh mal
Delphi-Quellcode:
Connect
von der Connection aus dem Thread raus, statt den Provider reinzuziehen! Also den Aufruf einfach mit
Delphi-Quellcode:
Synchronize
auslagern.

exchange 30. Nov 2016 07:53

AW: Multithreading (Access Violation)
 
Hi,
hatte einen Beiträg im Hersteller Forum plaziert.

http://forums.devart.com/viewtopic.php?f=28&t=34614

Wie es da weiter geht - abwarten. Die Rückmeldung von denen sieht mir aber eher nach einem Fehler bei denen aus.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:45 Uhr.

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