![]() |
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:
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).
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; 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 |
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.
|
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; |
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 |
AW: Multithreading (Access Violation)
Zeig doch mal Deinen gesamten Quelltext! So ist es doch nur ein Rätseln.
|
AW: Multithreading (Access Violation)
Hallo,
wo ist das Synchronize beim Zugriff das das Memo? |
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 |
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. |
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: ![]() Sherlock |
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:
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);
procedure TForm1.Button1Click(Sender: TObject);
begin Thread1.Resume; Thread2.Resume; end; 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 |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:20 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