Hello world, i write my multithread application (xe6) that access at simultaneus websites , but i have random this error: Exception class EAccessViolation with message 'Access violation at address 0000000000406B3E in module 'WebT.exe'. Read of address 0000001300000248'. Process WebT.exe (2456) when I see the call stack I have this story :000007fefda6b3dd System.NotifyNonDelphiException(???,???) System._DelphiExceptionHandler($12D9C0,1244192,$12D4D0,$12CE80) :00000000779C91AD ; ntdll.dll :00000000779B8BAF ; ntdll.dll :00000000779EDB38 ; ntdll.dll System.SysGetMem(???) System._GetMem(???) System._NewUnicodeString(172) System.InternalUStrCatN('black reality teatro furio camillo ~~-~~ ~~~~~~ ~~~~ iv edizione l’associazione semivolanti, in collaborazione con l’archimandrita, presenterà a roma il progetto black… ',3,$12DC00 {' '}) System._UStrCatN('black reality teatro furio camillo ~~-~~ ~~~~~~ ~~~~ iv edizione l’associazione semivolanti, in collaborazione con l’archimandrita, presenterà a roma il progetto black… ',3) AccessoWeb.CercaDateStg('black reality teatro furio camillo ~~-~~ ~~~~~~ ~~~~ iv edizione l’associazione semivolanti, in collaborazione con l’archimandrita, presenterà a roma il progetto black… ',32325) the last row is the last instruction of my program: if I clik on last line i have my last instruction that is simply: OrigStg := Stg; //booth var are string format or Stg := StringReplace(Stg, Car, Canc, []); or ............. (all times are strings operation) but it change all times. The common stack call in all errors is this last part: System.NotifyNonDelphiException(???,???) System._DelphiExceptionHandler($12D8D0,1244192,$12D3E0,$12CD90) :00000000779C91AD ; ntdll.dll :00000000779B8BAF ; ntdll.dll :00000000779EDB38 ; ntdll.dll System.SysGetMem(???) the problem is the ntdll.dll? can we help me...? i'm desperate! tx Lorenzo
![]() |
0 |
![]() |
Lorenzo Crivellaro wrote: > Hello world, > i write my multithread application (xe6) that access at simultaneus > websites , but i have random this error: > > Exception class EAccessViolation with message 'Access violation at > address 0000000000406B3E in module 'WebT.exe'. Read of address > 0000001300000248'. Process WebT.exe (2456) > > when I see the call stack I have this story > > :000007fefda6b3dd > System.NotifyNonDelphiException(???,???) > System._DelphiExceptionHandler($12D9C0,1244192,$12D4D0,$12CE80) > :00000000779C91AD ; ntdll.dll > :00000000779B8BAF ; ntdll.dll > :00000000779EDB38 ; ntdll.dll You can ignore that, that part of the call stack comes from the exception processing. > System.SysGetMem(???) That is the source of the exception. You said that you have a multithreaded application. Are you using TThread descendents or a different threading framework? Does the application use DLLs (other than the system DLLs)? If you use TThread descendents then the memory manager should be automatically configure to operate in a thread-safe manner. But that does not automatically make *all* operations done with compiler-managed datatypes (like string) thread-safe! If you share string variables between threads you still have to serialize access to them yourself, or you may run into problems like the one you are having now... -- Peter Below (TeamB)
![]() |
0 |
![]() |
> > -- > Peter Below (TeamB) Hello, > Are you using TThread descendents or a different threading framework? For multithread I use TThread descendents ( TMultiWeb = class(TThread) ) > Does the application use DLLs (other than the system DLLs)? No in this moment the application use only system dlls. I use only a global integer variable to count the thread active... but if i cancel this var i have the same access violation problem,.. i post my multithread code: constructor TMultiWeb.Create(Url: String; Mem: Boolean; Nom: String = ''; StTime: TDateTime = 0); begin inherited Create(False); // Inc(ElabMultiWeb); FUrl := TIdURI.URLEncode(Url); FNom := Nom; FMem := Mem; FStTime := StTime; Sito := ''; EndTime := 0; //Se si vuole il sito in memoria deve essere fatto il free dal processo chiamante: if (Mem) then FreeOnTerminate := False else FreeOnTerminate := True; end; {TMultiWeb.Create} procedure TMultiWeb.Execute; var Web: TIdHTTP; hIOHand: TIdSSLIOHandlerSocketOpenSSL; begin //Il Thread attende che venga raggiunta l'ora di esecuzione (se indicata): while (Now < FStTime) do //or (ElabMultiWeb > MAX_MULTI_WEB) do Application.ProcessMessages; Web := TIdHTTP.Create(nil); hIOHand := TIdSSLIOHandlerSocketOpenSSL.Create(nil); hIOHand.SSLOptions.Method := sslvTLSv1; Web.IOHandler := hIOHand; Web.HandleRedirects := True; Web.Request.UserAgent := INET_USERAGENT; //Custom user agent string Web.RedirectMaximum := INET_REDIRECT_MAX; //Maximum redirects Web.HandleRedirects := INET_REDIRECT_MAX <> 0; //Handle redirects Web.ReadTimeOut := INET_TIMEOUT_SECS * 1000; //Read timeout msec try Sito := Web.Get(FUrl); //Do the request except Sito := 'Errore accesso web'; end; Web.Free; hIOHand.Free; if (not FMem) then Synchronize(ScriviFile); EndTime := Now; // Dec(ElabMultiWeb); end; {TMultiWeb.Execute} Thankyou for your attention! Lorenzo
![]() |
0 |
![]() |
> > -- > Peter Below (TeamB) Hello, > Are you using TThread descendents or a different threading framework? For multithread I use TThread descendents ( TMultiWeb = class(TThread) ) > Does the application use DLLs (other than the system DLLs)? No in this moment the application use only system dlls. I use only a global integer variable to count the thread active... but if i cancel this var i have the same access violation problem,.. i post my multithread code: constructor TMultiWeb.Create(Url: String; Mem: Boolean; Nom: String = ''; StTime: TDateTime = 0); begin inherited Create(False); // Inc(ElabMultiWeb); FUrl := TIdURI.URLEncode(Url); FNom := Nom; FMem := Mem; FStTime := StTime; Sito := ''; EndTime := 0; //Se si vuole il sito in memoria deve essere fatto il free dal processo chiamante: if (Mem) then FreeOnTerminate := False else FreeOnTerminate := True; end; {TMultiWeb.Create} procedure TMultiWeb.Execute; var Web: TIdHTTP; hIOHand: TIdSSLIOHandlerSocketOpenSSL; begin //Il Thread attende che venga raggiunta l'ora di esecuzione (se indicata): while (Now < FStTime) do //or (ElabMultiWeb > MAX_MULTI_WEB) do Application.ProcessMessages; Web := TIdHTTP.Create(nil); hIOHand := TIdSSLIOHandlerSocketOpenSSL.Create(nil); hIOHand.SSLOptions.Method := sslvTLSv1; Web.IOHandler := hIOHand; Web.HandleRedirects := True; Web.Request.UserAgent := INET_USERAGENT; //Custom user agent string Web.RedirectMaximum := INET_REDIRECT_MAX; //Maximum redirects Web.HandleRedirects := INET_REDIRECT_MAX <> 0; //Handle redirects Web.ReadTimeOut := INET_TIMEOUT_SECS * 1000; //Read timeout msec try Sito := Web.Get(FUrl); //Do the request except Sito := 'Errore accesso web'; end; Web.Free; hIOHand.Free; if (not FMem) then Synchronize(ScriviFile); EndTime := Now; // Dec(ElabMultiWeb); end; {TMultiWeb.Execute} and this is the class declaration: TMultiWeb = class(TThread) private FUrl: String; //Inp: URl a cui accedere FNom: String; //Inp: Nome del file da salvare (può contenete un numero o stringa significativa) FMem: Boolean; //Inp: se True lavora in memoria, altrimenti scrive su file FStTime: TDateTime; //Inp: giorno e ora di partenza per effettuare l'accesso all'url procedure ScriviFile; protected procedure Execute; override; public Sito: String; //Out: Contiene l'html del sito web a cui si è fatto l'accesso EndTime: TDateTime; //Out: Viene impostato con l'orario di quando è terminato l'accesso constructor Create(Url: String; Mem: Boolean; Nom: String = ''; StTime: TDateTime = 0); end; Thankyou for your attention! Lorenzo Edited by: Lorenzo Crivellaro on Aug 4, 2015 9:57 AM
![]() |
0 |
![]() |
> > -- > Peter Below (TeamB) Hello, > Are you using TThread descendents or a different threading framework? For multithread I use TThread descendents ( TMultiWeb = class(TThread) ) > Does the application use DLLs (other than the system DLLs)? No in this moment the application use only system dlls. I use only a global integer variable to count the thread active... but if i cancel this var i have the same access violation problem,.. i post my multithread code (I hope can help to solve the problem): constructor TMultiWeb.Create(Url: String; Mem: Boolean; Nom: String = ''; StTime: TDateTime = 0); begin inherited Create(False); // Inc(ElabMultiWeb); FUrl := TIdURI.URLEncode(Url); FNom := Nom; FMem := Mem; FStTime := StTime; Sito := ''; EndTime := 0; //Se si vuole il sito in memoria deve essere fatto il free dal processo chiamante: if (Mem) then FreeOnTerminate := False else FreeOnTerminate := True; end; {TMultiWeb.Create} procedure TMultiWeb.Execute; var Web: TIdHTTP; hIOHand: TIdSSLIOHandlerSocketOpenSSL; begin //Il Thread attende che venga raggiunta l'ora di esecuzione (se indicata): while (Now < FStTime) do //or (ElabMultiWeb > MAX_MULTI_WEB) do Application.ProcessMessages; Web := TIdHTTP.Create(nil); hIOHand := TIdSSLIOHandlerSocketOpenSSL.Create(nil); hIOHand.SSLOptions.Method := sslvTLSv1; Web.IOHandler := hIOHand; Web.HandleRedirects := True; Web.Request.UserAgent := INET_USERAGENT; //Custom user agent string Web.RedirectMaximum := INET_REDIRECT_MAX; //Maximum redirects Web.HandleRedirects := INET_REDIRECT_MAX <> 0; //Handle redirects Web.ReadTimeOut := INET_TIMEOUT_SECS * 1000; //Read timeout msec try Sito := Web.Get(FUrl); //Do the request except Sito := 'Errore accesso web'; end; Web.Free; hIOHand.Free; if (not FMem) then Synchronize(ScriviFile); EndTime := Now; // Dec(ElabMultiWeb); end; {TMultiWeb.Execute} and this is the class declaration: TMultiWeb = class(TThread) private FUrl: String; //Inp: URl a cui accedere FNom: String; //Inp: Nome del file da salvare (può contenete un numero o stringa significativa) FMem: Boolean; //Inp: se True lavora in memoria, altrimenti scrive su file FStTime: TDateTime; //Inp: giorno e ora di partenza per effettuare l'accesso all'url procedure ScriviFile; protected procedure Execute; override; public Sito: String; //Out: Contiene l'html del sito web a cui si è fatto l'accesso EndTime: TDateTime; //Out: Viene impostato con l'orario di quando è terminato l'accesso constructor Create(Url: String; Mem: Boolean; Nom: String = ''; StTime: TDateTime = 0); end; Thankyou for your attention! Lorenzo Edited by: Lorenzo Crivellaro on Aug 4, 2015 9:57 AM Edited by: Lorenzo Crivellaro on Aug 4, 2015 9:59 AM
![]() |
0 |
![]() |
Lorenzo Crivellaro wrote: > > Are you using TThread descendents or a different threading > > framework? > For multithread I use TThread descendents ( TMultiWeb = > class(TThread) ) OK, so the memory manager should be configured to be threadsafe. > procedure TMultiWeb.Execute; > var > Web: TIdHTTP; > hIOHand: TIdSSLIOHandlerSocketOpenSSL; > begin > //Il Thread attende che venga raggiunta l'ora di esecuzione (se indicata): > while (Now < FStTime) do //or (ElabMultiWeb > MAX_MULTI_WEB) do > Application.ProcessMessages; Argh! Why are you doing that??? ProcessMessages should only be used in the main thread context, and even there it is a bad idea! To wait for something in a secondary thread you use Sleep, and your loop condition should also check the terminated property and bail out if it is true: while (Now < FStTime) and not Terminated do Sleep(50); // select an appriopriate wait interval if Terminated then Exit; > > Web := TIdHTTP.Create(nil); > hIOHand := TIdSSLIOHandlerSocketOpenSSL.Create(nil); The code using these two objects needs to be wrapped into a try finally block to make sure these two objects are destroyed even if something goes wrong before you get to call web.get. Unlikely in this case, I know, but it is a good habit to get into, especially if you work with classes that manage external resources, like socket handles or files. Objects should also be destroyed in the inverse sequence they are created in. I would structure this code section as hIOHand := nil; Web := TIDHttp.Create(nil); try hIOHand := TIdSSLIOHandlerSocketOpenSSL.Create(nil); hIOHand.SSLOptions.Method := sslvTLSv1; Web.IOHandler := hIOHand; Web.HandleRedirects := True; Web.Request.UserAgent := INET_USERAGENT; //Custom user agent string Web.RedirectMaximum := INET_REDIRECT_MAX; //Maximum redirects Web.HandleRedirects := INET_REDIRECT_MAX <> 0; //Handle redirects Web.ReadTimeOut := INET_TIMEOUT_SECS * 1000; //Read timeout msec try Sito := Web.Get(FUrl); //Do the request except Sito := 'Errore accesso web'; end; finally hIOHand.Free; Web.Free; end; if (not FMem) then Synchronize(ScriviFile); EndTime := Now; // Dec(ElabMultiWeb); end; {TMultiWeb.Execute} -- Peter Below (TeamB)
![]() |
0 |
![]() |
> Peter Below (TeamB) Hello Peter, i adjust my routine multithread as your instruction (im happy to have a correct routine), but i found the problem in an other instructions: Canc := StringOfChar('~', Length(Car)); ArrG[Num].Psz := I - Length(Car) - 1; ArrG[Num].Lng := Length(Car); ArrG[Num].Org := Car; Stg := StringReplace(Stg, Car, Canc, []); ArrG[Num].Num := StrToInt(Car); Car := ''; Inc(Num); if (I2 >= High(ArrG)) then SetLength(ArrG, Length(ArrG)+100); in the last if I used a wrong variable I2 and not the correct Num.... thankyou for your precius information... but i have a question for you: > while (Now < FStTime) and not Terminated do > Sleep(50); // select an appriopriate wait interval > if Terminated then Exit; why do you use Terminated var if is impossible that the routine is terminated (we are inside the routine) or terminated indicate another information? what is the correct way to control a max number of multithread that the program run in the same time? i used an external var... but i think in not a good idea Lorenzo Edited by: Lorenzo Crivellaro on Aug 5, 2015 2:46 PM
![]() |
0 |
![]() |
Lorenzo Crivellaro wrote: > Hello Peter, > i adjust my routine multithread as your instruction (im happy to > have a correct routine), but i found the problem in an other > instructions: Glad you found the source of the problem. > thankyou for your precius information... but i have a question for > you: > > > while (Now < FStTime) and not Terminated do > > Sleep(50); // select an appriopriate wait interval > > if Terminated then Exit; > > why do you use Terminated var if is impossible that the routine is > terminated (we are inside the routine) or terminated indicate another > information? A thread can be terminated from outside, e.g. when the application is closing and some code tries to Free the thread object. The default TThread destructor calls Terminate and then waits for the thread to get out of the Execute method. If said method does not check for Terminated this wait will never return and thus your application will not end normally, or only after a lengthy interval. Checking Terminated regularly inside a thread's Execute method is another habit one should cultivate <g>. > what is the correct way to control a max number of multithread that > the program run in the same time? i used an external var... but i > think in not a good idea If you want to have the counter internal to the thread class, use a private class var. Make sure to use a thread-safe mechanism to increment and decrement this variable. The TInterlocked class has Increment and Decrement methods that are thread-safe, other than Inc and Dec. Those are only safe for types were the operation is atomic on the machine code level, and that is only guaranteed for byte, as far as I know. Depends on the CPU... However, a simple counter is still vulnerable to race conditions in a multithreaded environment, since you have to use it in a two-step manner: check its value, if below the max number, increment it and create the new thread, else bail out. Between the test and the increment another thread may have jumped in (unless threads are only created by one single application thread, then this is not a problem). You can mitigate that by using TInterlocked.CompareExchange for the incrementation, that allows you to detect whether the counter has been altered by another thread after you got its value first. Using a TSemaphore instead of a counter does not have this problem, but it has another: If the thread aiming to create a new worker cannot acquire the semaphore because the maximum number of allowed threads has been reached the thread will be blocked until one of the running threads ends and releases the semaphore again. -- Peter Below (TeamB)
![]() |
0 |
![]() |
Lorenzo Crivellaro wrote: > Hello Peter, > i adjust my routine multithread as your instruction (im happy to > have a correct routine), but i found the problem in an other > instructions: Glad you found the source of the problem. > thankyou for your precius information... but i have a question for > you: > > > while (Now < FStTime) and not Terminated do > > Sleep(50); // select an appriopriate wait interval > > if Terminated then Exit; > > why do you use Terminated var if is impossible that the routine is > terminated (we are inside the routine) or terminated indicate another > information? A thread can be terminated from outside, e.g. when the application is closing and some code tries to Free the thread object. The default TThread destructor calls Terminate and then waits for the thread to get out of the Execute method. If said method does not check for Terminated this wait will never return and thus your application will not end normally, or only after a lengthy interval. Checking Terminated regularly inside a thread's Execute method is another habit one should cultivate <g>. > what is the correct way to control a max number of multithread that > the program run in the same time? i used an external var... but i > think in not a good idea If you want to have the counter internal to the thread class, use a private class var. Make sure to use a thread-safe mechanism to increment and decrement this variable. The TInterlocked class has Increment and Decrement methods that are thread-safe, other than Inc and Dec. Those are only safe for types were the operation is atomic on the machine code level, and that is only guaranteed for byte, as far as I know. Depends on the CPU... However, a simple counter is still vulnerable to race conditions in a multithreaded environment, since you have to use it in a two-step manner: check its value, if below the max number, increment it and create the new thread, else bail out. Between the test and the increment another thread may have jumped in (unless threads are only created by one single application thread, then this is not a problem). You can mitigate that by using TInterlocked.CompareExchange for the incrementation, that allows you to detect whether the counter has been altered by another thread after you got its value first. Using a TSemaphore instead of a counter does not have this problem, but it has another: If the thread aiming to create a new worker cannot acquire the semaphore because the maximum number of allowed threads has been reached the thread will be blocked until one of the running threads ends and releases the semaphore again. -- Peter Below (TeamB)
![]() |
0 |
![]() |