Login ProductsSalesSupportDownloadsAbout |
Home » Technical Support » DBISAM Technical Support » Support Forums » DBISAM General » View Thread |
Messages 11 to 20 of 22 total |
OT: Problem with threads |
Sun, Nov 4 2012 11:42 PM | Permanent Link |
Raul Team Elevate | On 11/4/2012 9:00 PM, Adam H. wrote:
> One thing I also learned that surprised me was that showmessage and > messagedlg are thread safe - so I can actually raise one if I want > within a thread for user intervention. What makes you think so? I believe they are not as both rely on VCL and forms etc - you'd need to use a OS level dialog for that (like MessageBox) > I have gotten to a stage after searching the net where I am handling > exceptions, but it's not freeing up the thread once it's completed. As a > result - the application still things the thread is running, and since I > don't want to close the app until threads have been completed (to avoid > corrupting any data on writes) I'm not sure where to go to from here. If you're handling the errors then your thread should free. There is no drp file so i can't open the project but looking at the source files i'm little confused on some aspects. The DMThread usage is little weird to me - you're using to launch a thread (startthread) and then thread itself creates one as well. You're using Synhronize AND postmessage - you only need to use one or the other (postmessage being better one). The thread OnTerminate runs in the context of the main thread so you should NOT be assigning it to ST.OnFinish but to TMainform handler. i wrote a quick and dirty version of this myself and attached to binary NG. The main form has 2 buttons - one to star the the thread and other to stop it or it will terminate itself once the progress reaches 100. This one assumes the trhead is created as needed and dies at the end. I think step one is to make sure your thread runs properly and does not call anything it should not (like any VCL commands). Handling exceptions in threads gets tricky as you need to decide what to do and if you need to notify user and get input you generally need to route this thru main thread using postmessage back and forth (to ensure fully non-blocking behaviour on both ends) and this minimally would require some kind of state machine in the thread. If all you want to do in the thread is to tell user you've failed then either use Windows.MessageBox or just set a public string variable in thread with proper message and terminate and then show the dialog in OnTerminate handler. Raul |
Mon, Nov 5 2012 12:35 AM | Permanent Link |
Adam H. | Hi Raul,
Thanks for your reply. >> One thing I also learned that surprised me was that showmessage and >> messagedlg are thread safe - so I can actually raise one if I want >> within a thread for user intervention. > > What makes you think so? I believe they are not as both rely on VCL and > forms etc - you'd need to use a OS level dialog for that (like MessageBox) Just something I read on the internet. (Oh - I can't believe I just said that!!!!) But I do recall somewhere someone saying that they were 'thread safe'. I did try it in a thread and it seemed to work OK without causing problems, but I have no need for it (well, except for throwing up error dialogs >> I have gotten to a stage after searching the net where I am handling >> exceptions, but it's not freeing up the thread once it's completed. As a >> result - the application still things the thread is running, and since I >> don't want to close the app until threads have been completed (to avoid >> corrupting any data on writes) I'm not sure where to go to from here. > > If you're handling the errors then your thread should free. > > There is no drp file so i can't open the project but looking at the > source files i'm little confused on some aspects. Sorry about that. I have uploaded another one with the drp file in there now... > The DMThread usage is little weird to me - you're using to launch a > thread (startthread) and then thread itself creates one as well. I can see your confusion. The thread doesn't create another new thread - it simply creates a datamodule (that is called DMThread. Probably very poor choice of naming creating the confusion). The fact that the thread is contained within the same unit as the Datamodule is probably a little confusing. I've actually done that deliberate as within my real application I want the one unit to contain all the information / procedures required within it to work. This way I can simply replace one unit and call the same command to change from existing 'non threaded' version to a threaded version. > You're using Synhronize AND postmessage - you only need to use one or > the other (postmessage being better one). Normally I have been using postmessage. I used syncronise only for the raising of the exception (which is the latest bit I have done so far). > The thread OnTerminate runs in the context of the main thread so you > should NOT be assigning it to ST.OnFinish but to TMainform handler. > i wrote a quick and dirty version of this myself <snip> Thanks very much for that. I've checked it out. It appears as though the main difference between mine and yours is that you contain the thread creation stuff within the main unit (frmmain), whereas I have it within a separate unit. The reason I am creating the datamodule (although probably not relivant in this particular example) is because the datamodule contains other components, such as TDBISamSession, DB, Tables, etc that it processes. I've taken all these out to try and reduce it to it's most 'basic' form at the moment. > Handling exceptions in threads gets tricky as you need to decide what to > do and if you need to notify user and get input you generally need to > route this thru main thread using postmessage back and forth (to ensure > fully non-blocking behaviour on both ends) and this minimally would > require some kind of state machine in the thread. For the exception - I effectively just want it to show an error dialog, alerting the user that a problem has occurred. (Preferably the actual error message itself), and then just close the thread down so it no longer exists. > If all you want to do in the thread is to tell user you've failed then > either use Windows.MessageBox or just set a public string variable in > thread with proper message and terminate and then show the dialog in > OnTerminate handler. I *think* that's what I'm doing with the application.showexception call. After doing this, it continues with the terminate call, but for some reason my application still things that the thread is there (although to be fair, terminated appears to be set to 'true'), but not freed (if I'm making sense)? Thanks for your help! Adam. |
Mon, Nov 5 2012 8:40 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Raul
>If all you want to do in the thread is to tell user you've failed then >either use Windows.MessageBox or just set a public string variable in >thread with proper message and terminate and then show the dialog in >OnTerminate handler. Or post a message number back to the main form which then shows the appropriate error message. Roy Lambert [Team Elevate] |
Mon, Nov 5 2012 8:45 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Adam
>>> One thing I also learned that surprised me was that showmessage and >>> messagedlg are thread safe - so I can actually raise one if I want >>> within a thread for user intervention. >> >> What makes you think so? I believe they are not as both rely on VCL and >> forms etc - you'd need to use a OS level dialog for that (like MessageBox) As Raul says they are basically just forms. The reason they havn't caused an error YET is that they simply haven't hit the right set of circumstances. >>> I have gotten to a stage after searching the net where I am handling >>> exceptions, but it's not freeing up the thread once it's completed. As a >>> result - the application still things the thread is running, and since I >>> don't want to close the app until threads have been completed (to avoid >>> corrupting any data on writes) I'm not sure where to go to from here. Woops - raise exception.create('Break here'); is not the way to handle exceptions in threads. Use try.. except .. end eg (untested) procedure TDMThread.DoSomething; var YY,XX,i : integer; begin XX:=0; try for i := 0 to 100 do begin if i = 17 then YY := i / XX; ST.progress := i; ST.UpdateProgressBar; sleep(20); end; except PostMessage(callinghandle,yourerrorhandler,errornum,1); Terminated := True; end; end; >> The DMThread usage is little weird to me - you're using to launch a >> thread (startthread) and then thread itself creates one as well. > >I can see your confusion. The thread doesn't create another new thread - >it simply creates a datamodule (that is called DMThread. Probably very >poor choice of naming creating the confusion). > >The fact that the thread is contained within the same unit as the >Datamodule is probably a little confusing. I've actually done that >deliberate as within my real application I want the one unit to contain >all the information / procedures required within it to work. This way I >can simply replace one unit and call the same command to change from >existing 'non threaded' version to a threaded version. I have no idea if a datamodule is thread safe or not. I ALWAYS instantiate all the database components I need within the thread, passing any needed information in as part of the constructor parameters. The TSendThread.Execute bit of code fills me with awe. procedure TSendThread.Execute; var TF : Tdmthread; begin try TF := Tdmthread.create(nil); TF.DoSomething; TF.free; beep; <<<<< no idea how this will get on with other threads Terminate; <<<< what does this refer to? If TF you've already freed it TF := nil; except HandleException; <<<<<<< all I can say is ouch. In theory the code will work (I think) but if my guess about the Terminate above is right it will trigger every time. end; end; I know you're trying to simplify things but if there's a way you can let me have a look at the full code I'll possibly be able to help. Alternatively I can send you the D6/DBISAM source (very old) for my email and news client which uses threads, or the D2006/ElevateDB email part of my current recruitment app both of which use threads and the Synapse library. Roy Lambert [Team Elevate] |
Mon, Nov 5 2012 8:58 AM | Permanent Link |
Raul Team Elevate | On 11/5/2012 12:35 AM, Adam H. wrote:
> But I do recall somewhere someone saying that they were 'thread safe'. I > did try it in a thread and it seemed to work OK without causing > problems, but I have no need for it (well, except for throwing up error > dialogs AFAIK they are based on VCL and as such not thread safe. App might compile and run still - non-thread safe does not mean there likely will be issues later on. > I can see your confusion. The thread doesn't create another new thread - > it simply creates a datamodule (that is called DMThread. Probably very > poor choice of naming creating the confusion). That is the right way to do it : - main thread should always create the thread(s) themselves - inside the thread execute you create the data module(s) > The fact that the thread is contained within the same unit as the > Datamodule is probably a little confusing. I've actually done that > deliberate as within my real application I want the one unit to contain > all the information / procedures required within it to work. This way I > can simply replace one unit and call the same command to change from > existing 'non threaded' version to a threaded version. That is OK as long as thread creates the DMs and main thread cannot touch them (since they are running in the thread and not main thread). > The reason I am creating the datamodule (although probably not relivant > in this particular example) is because the datamodule contains other > components, such as TDBISamSession, DB, Tables, etc that it processes. > I've taken all these out to try and reduce it to it's most 'basic' form > at the moment. Again that is exactly the way to do it as long as all interaction with the DM is done in new thread code only. > For the exception - I effectively just want it to show an error dialog, > alerting the user that a problem has occurred. (Preferably the actual > error message itself), and then just close the thread down so it no > longer exists. The best way to do this is to post a message to the main thread and show message there (using either Roy's great suggestion or just store the error message ina thread string variable and onterminate will check it and if it's non-blank it will display it). > I *think* that's what I'm doing with the application.showexception call. > After doing this, it continues with the terminate call, but for some > reason my application still things that the thread is there (although to > be fair, terminated appears to be set to 'true'), but not freed (if I'm > making sense)? Application.ShowException is using showmessage which is not thread safe so don't do that from within the thread but do it from main thread (either postmessage event handler on from on onterminate handler). Raul |
Mon, Nov 5 2012 9:39 AM | Permanent Link |
Raul Team Elevate | On 11/5/2012 8:45 AM, Roy Lambert wrote:
> I have no idea if a datamodule is thread safe or not. I ALWAYS instantiate all the database components I need within the thread, passing any needed information in as part of the constructor parameters. DM is threadsafe- our main server app is 20+ threads and each thread has 1-5 DMs depending on the need. I found the DMs really useful since you can reuse the DM logic by creating it in multiple threads - so all my threads above need DB access and all create their own instance of the same DB DM. However like you said one needs to follow the DBISAM/EDB/component X rules for multithreaded apps to ensure unique sessions etc. Hence the DM itself is thread safe but you still need to be thread safe in what you do there. Raul |
Mon, Nov 5 2012 9:55 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Raul
That's a lot of datamodules Are the 20+ threads all the same? Roy |
Mon, Nov 5 2012 12:07 PM | Permanent Link |
Raul Team Elevate | No in this case they are all different - most of the DMs are fairly
light and provide just DBISAM access meaning Session, db etc (either for in-mem or C/S connections). I also have a another app where we need to do outbound TCP connections to mobile devices and there the threads and DMs are all identical and i use a variable pool of them to do the connection - most we've tested with is 100 threads (and DM's) doing concurrent outbound connections at the same time. Funny enough one of the main problems was main thread running close to 100% at times due to worker threads using postmessage to main thread which updated the UI - UI update is really slow in this scenario (relatively speaking) so bottleneck was there. None of this of course affected the worker threads. Raul > Raul > > > That's a lot of datamodules > > Are the 20+ threads all the same? > > Roy > |
Thu, Nov 8 2012 9:50 PM | Permanent Link |
Adam H. | Hi Roy,
>>>> One thing I also learned that surprised me was that showmessage and >>>> messagedlg are thread safe - so I can actually raise one if I want >>>> within a thread for user intervention. >>> >>> What makes you think so? I believe they are not as both rely on VCL and >>> forms etc - you'd need to use a OS level dialog for that (like MessageBox) > > As Raul says they are basically just forms. The reason they havn't caused an error YET is that they simply haven't hit the right set of circumstances. OK - thanks guys. I'll have to stop believing everything I read on the internet. <vbg> > Woops - raise exception.create('Break here'); is not the way to handle exceptions in threads. Use try.. except .. end eg (untested) > > procedure TDMThread.DoSomething; > var > YY,XX,i : integer; > begin > XX:=0; > try > for i := 0 to 100 do > begin > if i = 17 then YY := i / XX; > ST.progress := i; > ST.UpdateProgressBar; > sleep(20); > end; > except > PostMessage(callinghandle,yourerrorhandler,errornum,1); > Terminated := True; > end; > end; OK - so effectively there is nothing different to exceptions than anything else - I should just trap them, and pass a message back to the main form. The code I got was from an example of how to handle exceptions in threads off the net. Once again - lead astray by the big www's. ;-( > I have no idea if a datamodule is thread safe or not. I ALWAYS instantiate all the database components I need within the thread, passing any needed information in as part of the constructor parameters. I believe they are - and actually find it much cleaner to keep everything on the datamodule. Just general preference I guess. > The TSendThread.Execute bit of code fills me with awe. > > procedure TSendThread.Execute; > var > TF : Tdmthread; > begin > try > TF := Tdmthread.create(nil); > TF.DoSomething; > TF.free; > beep; <<<<< no idea how this will get on with other threads > Terminate; <<<< what does this refer to? If TF you've already freed it > TF := nil; > except > HandleException; <<<<<<< all I can say is ouch. In theory the code will work (I think) but if my guess about the Terminate above is right it will trigger every time. > end; > end; > > I know you're trying to simplify things but if there's a way you can let me have a look at the full code I'll possibly be able to help. Alternatively I can send you the D6/DBISAM source (very old) for my email and news client which uses threads, or the D2006/ElevateDB email part of my current recruitment app both of which use threads and the Synapse library. That could be difficult. There are more than 500 separate forms alone for this particular project, not including shared units used elsewhere. Although if you only need the code for the particular unit - I could definitely shoot that through to you. But once again - it's got quite a bit in there that is (IMO) not relevant to threads which is why I'm trying to simplify what I'm doing to only thread related issues within the example project. That way you can at least not only see what I'm doing, but also compile and run it too to see the same results I'm getting. Cheers Adam. |
Thu, Nov 8 2012 9:56 PM | Permanent Link |
Adam H. | Hi Raul,
>> I can see your confusion. The thread doesn't create another new thread - >> it simply creates a datamodule (that is called DMThread. Probably very >> poor choice of naming creating the confusion). > > That is the right way to do it : > - main thread should always create the thread(s) themselves > - inside the thread execute you create the data module(s) I think that's what I'm doing already. 1) Main thread calls a procedure in the DMThread unit that creates the actual thread. 2) The actual thread then creates the physical TDataModule form associated with the DMThread unit. I could move the procedure to create the actual thread out of DMThread and into Mainform, however I would like to avoid this where possible. Within my applications, I create most of my forms and data modules by calling a procedure contained within the actual unit myself. While I think this may not be 'usual practise', I find it cleaner, in particularly because in many parts of my application, a form can be called up from many different units. I figure instead of writing the same code over and over again in the various individual units wanting to create the form, I just write the code once - in the actual unit itself. That way there's only one line of code to create the unit from all the other units within the project. >> The fact that the thread is contained within the same unit as the >> Datamodule is probably a little confusing. I've actually done that >> deliberate as within my real application I want the one unit to contain >> all the information / procedures required within it to work. This way I >> can simply replace one unit and call the same command to change from >> existing 'non threaded' version to a threaded version. > > That is OK as long as thread creates the DMs and main thread cannot > touch them (since they are running in the thread and not main thread). Excellent. That makes sense - thanks. > > The reason I am creating the datamodule (although probably not relivant >> in this particular example) is because the datamodule contains other >> components, such as TDBISamSession, DB, Tables, etc that it processes. >> I've taken all these out to try and reduce it to it's most 'basic' form >> at the moment. > > Again that is exactly the way to do it as long as all interaction with > the DM is done in new thread code only. Well, interaction is done either within the thread code, or within procedures / methods that are local (private) to the actual DM that's being created - which I think is OK, as that would still be part of that particular thread, and not accessed from outside / anywhere else. > The best way to do this is to post a message to the main thread and show > message there (using either Roy's great suggestion or just store the > error message ina thread string variable and onterminate will check it > and if it's non-blank it will display it). No worries - I shall go with that then. >> I *think* that's what I'm doing with the application.showexception call. >> After doing this, it continues with the terminate call, but for some >> reason my application still things that the thread is there (although to >> be fair, terminated appears to be set to 'true'), but not freed (if I'm >> making sense)? > > Application.ShowException is using showmessage which is not thread safe > so don't do that from within the thread but do it from main thread > (either postmessage event handler on from on onterminate handler). OK - thanks for the advise! I'll go back when I've got a few minutes, and re-write it and try again. Cheers Adam. |
« Previous Page | Page 2 of 3 | Next Page » |
Jump to Page: 1 2 3 |
This web page was last updated on Tuesday, May 14, 2024 at 07:14 PM | Privacy PolicySite Map © 2024 Elevate Software, Inc. All Rights Reserved Questions or comments ? E-mail us at info@elevatesoft.com |