Home » Eclipse Projects » Eclipse Platform » All tied up with threads!
All tied up with threads! [message #282634] |
Wed, 16 March 2005 23:03  |
Eclipse User |
|
|
|
Originally posted by: Lamont_Gilbert.rigidsoftware.com
I have a database graphical application. I have commands that are
executed which need info from the database. So during the execution I
use the progress service and run the commands in busyCursorWhile(runnable).
The problem is the commands may cause the models to be adjusted, which
in turn will fire some events, which in tern will want to update the
editParts that represent the models. During this editPart update,
naturaly I am hitting the database again, so I want to use the busy cursor.
The end result is that I am calling busyCursorWhile during the execution
of another session of busyCursorWhile, and Eclipse does not seem to like
that.
Is there any effective way to call this twice, or perhaps can eclipse
know the thread calling the busyCursorWhile is already the
busyCursorWhile thread???
Is there any other way?
Thanks for the tips.
CL
|
|
|
Re: All tied up with threads! [message #282638 is a reply to message #282634] |
Thu, 17 March 2005 00:06   |
Eclipse User |
|
|
|
Originally posted by: Lamont_Gilbert.rigidsoftware.com
what I have done is to check
Display.getCurrent(), and if that is not null it means I am currently
running in the UI thread. In which case I just stay there and execute
my code with
IProgressService.run(false,false,runnable);
But if Display.getCurrent() is null, then it means I am not in the UI
thread and so I run my code with
IProgressService.busyCursorWhile(runnable);
It works.
This leads me to believe busyCursorWhile is going to execute my code in
the UI thread too?? So I have just ensured that my code will always be
run in the UI thread?
CL
CL [dnoyeb] Gilbert wrote:
> I have a database graphical application. I have commands that are
> executed which need info from the database. So during the execution I
> use the progress service and run the commands in busyCursorWhile(runnable).
>
> The problem is the commands may cause the models to be adjusted, which
> in turn will fire some events, which in tern will want to update the
> editParts that represent the models. During this editPart update,
> naturaly I am hitting the database again, so I want to use the busy cursor.
>
> The end result is that I am calling busyCursorWhile during the execution
> of another session of busyCursorWhile, and Eclipse does not seem to like
> that.
>
> Is there any effective way to call this twice, or perhaps can eclipse
> know the thread calling the busyCursorWhile is already the
> busyCursorWhile thread???
>
> Is there any other way?
>
>
>
> Thanks for the tips.
>
>
> CL
|
|
|
Re: All tied up with threads! [message #282668 is a reply to message #282638] |
Thu, 17 March 2005 09:01   |
Eclipse User |
|
|
|
Originally posted by: Lamont_Gilbert.rigidsoftware.com
CL [dnoyeb] Gilbert wrote:
> what I have done is to check
>
> Display.getCurrent(), and if that is not null it means I am currently
> running in the UI thread. In which case I just stay there and execute
> my code with
>
> IProgressService.run(false,false,runnable);
>
> But if Display.getCurrent() is null, then it means I am not in the UI
> thread and so I run my code with
>
> IProgressService.busyCursorWhile(runnable);
>
> It works.
>
No, it actually does not work. It appears that both of these methods
must be called from within the UI thread. (Javadoc needs to be updated
to reflect this fact!) The first gives you the chance to run your
runnable in the UI thread or branch out. The busyCursorWhile does not
give you a choice but always branches into a non-UI thread.
Therefore, after you call busyCursorWhile you will be running in a
non-UI thread. So if you try to call it a 2nd time, within the
execution of the first it will fail with illegal thread access.
So now I am stuck with the weird UI conundrum. How do I get a Display
so I can run in the UI thread since Displays are only given out to those
already running within the UI thread?
The issue is, if I am runing something with the busyCursorWhile, that
puts me out of the UI thread. Then within that thread I have an
occasion to access the DB again. anytime i access the db i want to open
a progress dialog.
I can assume that if a db access method is being called outside of the
UI thread, then there is probably already a busyCursor up, but its a
heck of an assumption... And anyway it makes my code a mess because
running in the UI thread I get to use the busyCursor which sends my
method a IProgressMonitor, but outside the UI thread This will be null,
so ill have to always check for null. Im definitely tied up here!
Help!
Cl
|
|
|
Re: All tied up with threads! [message #282673 is a reply to message #282668] |
Thu, 17 March 2005 09:32   |
Eclipse User |
|
|
|
CL,
We have similar issues in the CVS plugin. What we do is use a background
job to perform all our remote accessing. This means that the UI will
still be live when the command is running and the user can still do
things while they wait for the operation to complete. For UI updating,
we have a second job that acts as an event handler. The background
access job will post UI update events (directly or indirectly through
model listeners) to the event handler. The event handler will then
serialize the UI updates. We also batch UI updates to avoid too much UI
flicker. Updates are performed by using Display#syncExec or
Display#asyncExec and we use BusyIndicator#showWhile within these calls
to get the busy cursor. You can have a look at the
BackgroundEventHandler class in the org.eclipse.team.core pligin if your
interested. It's not API but illustrates how the Team/CVS UI update
event handling works.
This may be a bit more work than you want to do (or may not match with
your desired behavior). The root of yours specific problem is that
IProgressService.run(false,false,runnable) will run in the UI thread if
launched from the UI thread but
IProgressService.busyCursorWhile(runnable) is never run in the UI
thread. If you want your operation to run entirely in the UI thread, you
can use Display#syncExec or asyncExec or use a WorkbenchJob. However, I
would discourage this as it may block the UI for a long time if the
operation is long running. A better approach is this:
- Use busyCursorWhile (or run) to wrap the entire operation (or a Job if
it coudl be run in the background)
- when UI updates are needed, use Display#asyncExec or a WorkbenchJob
(or Display#syncExec if synchronous updating is required).
- if the UI updating could be hit from outside an operation, you can use
the BusyIndicator#showWhile within the asyncExec
One warning about the UI updating. If your model does not batch change
events then you may end up with many small UI updates which can have a
negative impact on usability (UI flicker and unresponsiveness). It is
for this reason that we sed a background job to batch UI updates.
Hope this helps
Michael
CL [dnoyeb] Gilbert wrote:
> CL [dnoyeb] Gilbert wrote:
>
>> what I have done is to check
>>
>> Display.getCurrent(), and if that is not null it means I am currently
>> running in the UI thread. In which case I just stay there and execute
>> my code with
>>
>> IProgressService.run(false,false,runnable);
>>
>> But if Display.getCurrent() is null, then it means I am not in the UI
>> thread and so I run my code with
>>
>> IProgressService.busyCursorWhile(runnable);
>>
>> It works.
>>
>
> No, it actually does not work. It appears that both of these methods
> must be called from within the UI thread. (Javadoc needs to be updated
> to reflect this fact!) The first gives you the chance to run your
> runnable in the UI thread or branch out. The busyCursorWhile does not
> give you a choice but always branches into a non-UI thread.
>
> Therefore, after you call busyCursorWhile you will be running in a
> non-UI thread. So if you try to call it a 2nd time, within the
> execution of the first it will fail with illegal thread access.
>
> So now I am stuck with the weird UI conundrum. How do I get a Display
> so I can run in the UI thread since Displays are only given out to those
> already running within the UI thread?
>
> The issue is, if I am runing something with the busyCursorWhile, that
> puts me out of the UI thread. Then within that thread I have an
> occasion to access the DB again. anytime i access the db i want to open
> a progress dialog.
>
> I can assume that if a db access method is being called outside of the
> UI thread, then there is probably already a busyCursor up, but its a
> heck of an assumption... And anyway it makes my code a mess because
> running in the UI thread I get to use the busyCursor which sends my
> method a IProgressMonitor, but outside the UI thread This will be null,
> so ill have to always check for null. Im definitely tied up here!
>
>
> Help!
>
>
>
> Cl
>
>
|
|
|
Re: All tied up with threads! [message #282688 is a reply to message #282673] |
Thu, 17 March 2005 11:37   |
Eclipse User |
|
|
|
Originally posted by: Lamont_Gilbert.rigidsoftware.com
Thanks for you very informative and detailed reply. I have responded
within.
Michael Valenta wrote:
> CL,
>
> We have similar issues in the CVS plugin. What we do is use a background
> job to perform all our remote accessing. This means that the UI will
> still be live when the command is running and the user can still do
> things while they wait for the operation to complete. For UI updating,
> we have a second job that acts as an event handler. The background
> access job will post UI update events (directly or indirectly through
> model listeners) to the event handler. The event handler will then
> serialize the UI updates. We also batch UI updates to avoid too much UI
> flicker. Updates are performed by using Display#syncExec or
> Display#asyncExec and we use BusyIndicator#showWhile within these calls
> to get the busy cursor. You can have a look at the
> BackgroundEventHandler class in the org.eclipse.team.core pligin if your
> interested. It's not API but illustrates how the Team/CVS UI update
> event handling works.
>
Unfortunately in my case, these are not job-able tasks. This is a
graphical program, and when you push delete, you don't want to let the
user then re-grab the object, only to have it deleted later on by a job.
You wan't the UI blocked.
I have learned though that there are different ways of blocking the UI.
Running in the UI 'blocks' it, but also prevents it from cleaning up
the interface. using busyCursorWhile, 'blocks' it, but allows it to
clean up the interface if/when necessary.
The 2nd thing I want is the progress dialog. But it looks like you only
get 1 progress dialog. So I can't for instance, start a call in
busyCursorWhile that fires an event that tries to again call
busyCursorWhile. Well I can, if I can get back into the UI thread with
Display.syncexec first. Which is what I am looking at doing now. This
way I always get a progress dialog and/or a busy cursor.
I think I will let each would-be caller of busyCursorWhile, provide a
display so I can get into the UI thread to make the call to
busyCursorWhile!?
> This may be a bit more work than you want to do (or may not match with
> your desired behavior). The root of yours specific problem is that
> IProgressService.run(false,false,runnable) will run in the UI thread if
> launched from the UI thread but
> IProgressService.busyCursorWhile(runnable) is never run in the UI
> thread. If you want your operation to run entirely in the UI thread, you
> can use Display#syncExec or asyncExec or use a WorkbenchJob. However, I
> would discourage this as it may block the UI for a long time if the
> operation is long running. A better approach is this:
>
> - Use busyCursorWhile (or run) to wrap the entire operation (or a Job if
> it coudl be run in the background)
> - when UI updates are needed, use Display#asyncExec or a WorkbenchJob
> (or Display#syncExec if synchronous updating is required).
> - if the UI updating could be hit from outside an operation, you can use
> the BusyIndicator#showWhile within the asyncExec
>
Well if I can call Display#asyncExec, I might as well use a WorkbenchJob
right? Anytime I hit the database, I am looking to get a progress
dialog. You never know when that thing can crash or something.
> One warning about the UI updating. If your model does not batch change
> events then you may end up with many small UI updates which can have a
> negative impact on usability (UI flicker and unresponsiveness). It is
> for this reason that we sed a background job to batch UI updates.
>
> Hope this helps
> Michael
>
>
> CL [dnoyeb] Gilbert wrote:
>
>>
>> No, it actually does not work. It appears that both of these methods
>> must be called from within the UI thread. (Javadoc needs to be updated
>> to reflect this fact!) The first gives you the chance to run your
>> runnable in the UI thread or branch out. The busyCursorWhile does not
>> give you a choice but always branches into a non-UI thread.
>>
>> Therefore, after you call busyCursorWhile you will be running in a
>> non-UI thread. So if you try to call it a 2nd time, within the
>> execution of the first it will fail with illegal thread access.
>>
>> So now I am stuck with the weird UI conundrum. How do I get a Display
>> so I can run in the UI thread since Displays are only given out to
>> those already running within the UI thread?
>>
>> The issue is, if I am runing something with the busyCursorWhile, that
>> puts me out of the UI thread. Then within that thread I have an
>> occasion to access the DB again. anytime i access the db i want to
>> open a progress dialog.
>>
>> I can assume that if a db access method is being called outside of the
>> UI thread, then there is probably already a busyCursor up, but its a
>> heck of an assumption... And anyway it makes my code a mess because
>> running in the UI thread I get to use the busyCursor which sends my
>> method a IProgressMonitor, but outside the UI thread This will be
>> null, so ill have to always check for null. Im definitely tied up here!
>>
>>
>> Help!
>>
>>
>>
>> Cl
>>
>>
>
|
|
|
Re: All tied up with threads! [message #282737 is a reply to message #282688] |
Fri, 18 March 2005 09:58   |
Eclipse User |
|
|
|
CL [dnoyeb] Gilbert wrote:
> Thanks for you very informative and detailed reply. I have responded
> within.
>
> Michael Valenta wrote:
>
>> CL,
>>
>> We have similar issues in the CVS plugin. What we do is use a
>> background job to perform all our remote accessing. This means that
>> the UI will still be live when the command is running and the user can
>> still do things while they wait for the operation to complete. For UI
>> updating, we have a second job that acts as an event handler. The
>> background access job will post UI update events (directly or
>> indirectly through model listeners) to the event handler. The event
>> handler will then serialize the UI updates. We also batch UI updates
>> to avoid too much UI flicker. Updates are performed by using
>> Display#syncExec or Display#asyncExec and we use
>> BusyIndicator#showWhile within these calls to get the busy cursor. You
>> can have a look at the BackgroundEventHandler class in the
>> org.eclipse.team.core pligin if your interested. It's not API but
>> illustrates how the Team/CVS UI update event handling works.
>>
>
> Unfortunately in my case, these are not job-able tasks. This is a
> graphical program, and when you push delete, you don't want to let the
> user then re-grab the object, only to have it deleted later on by a job.
> You wan't the UI blocked.
You may be interested to know that deletes launched from the Resource
Navigator occur in the background (in 3.1). This is possible for two
reasons:
1) Resources act as scheduling rules so that multiple jobs cannot modify
the same resources (or resource tree). You can think of this as blocking
access to the resource being deleted instead of all resources and the
entire IDE.
2) It is fairly easy for a user to understand that any descendants of
the selected resource will be deleted so they can expect them to
disappear in a reasonably short time.
However, this may not make sense in you context. I was only mentioning
it as a case in point.
>
> I have learned though that there are different ways of blocking the UI.
> Running in the UI 'blocks' it, but also prevents it from cleaning up
> the interface. using busyCursorWhile, 'blocks' it, but allows it to
> clean up the interface if/when necessary.
>
> The 2nd thing I want is the progress dialog. But it looks like you only
> get 1 progress dialog. So I can't for instance, start a call in
> busyCursorWhile that fires an event that tries to again call
> busyCursorWhile. Well I can, if I can get back into the UI thread with
> Display.syncexec first. Which is what I am looking at doing now. This
> way I always get a progress dialog and/or a busy cursor.
>
> I think I will let each would-be caller of busyCursorWhile, provide a
> display so I can get into the UI thread to make the call to
> busyCursorWhile!?
>
>
>> This may be a bit more work than you want to do (or may not match with
>> your desired behavior). The root of yours specific problem is that
>> IProgressService.run(false,false,runnable) will run in the UI thread
>> if launched from the UI thread but
>> IProgressService.busyCursorWhile(runnable) is never run in the UI
>> thread. If you want your operation to run entirely in the UI thread,
>> you can use Display#syncExec or asyncExec or use a WorkbenchJob.
>> However, I would discourage this as it may block the UI for a long
>> time if the operation is long running. A better approach is this:
>>
>> - Use busyCursorWhile (or run) to wrap the entire operation (or a Job
>> if it coudl be run in the background)
>> - when UI updates are needed, use Display#asyncExec or a WorkbenchJob
>> (or Display#syncExec if synchronous updating is required).
>> - if the UI updating could be hit from outside an operation, you can
>> use the BusyIndicator#showWhile within the asyncExec
>>
>
> Well if I can call Display#asyncExec, I might as well use a WorkbenchJob
> right? Anytime I hit the database, I am looking to get a progress
> dialog. You never know when that thing can crash or something.
Yes, you can use WorkbenchJob instead of asyncExec. I'm a bit confused
about the statement about getting a progress dialog each time you hit
the database. The way I would state it is that I want a progress dialog
up for the duration of any user triggered operations. It seems to me
that you are trying to launch progress dialogs from various points in
your application, some of which may be nested. I think this is a poor
design choice. You need to understand all the points where the user
triggered an operation and open progress dialogs there (or use
busyCursorWhile). The IProgressMonitor obtained at that time should then
be passed through all the subsequent operation calls and any UI updates
can be made using syncExec, asyncExec or WorkbenchJob. If it is not
possible to pass the IProgressMonitor through the operation than you
have a real problem since there will be no way to provide a responsive
UI (since, as you witnessed, you can't have multiple progress dialogs
visible).
>
>
>> One warning about the UI updating. If your model does not batch change
>> events then you may end up with many small UI updates which can have a
>> negative impact on usability (UI flicker and unresponsiveness). It is
>> for this reason that we sed a background job to batch UI updates.
>>
>> Hope this helps
>> Michael
>>
>>
>> CL [dnoyeb] Gilbert wrote:
>>
>
>>>
>>> No, it actually does not work. It appears that both of these methods
>>> must be called from within the UI thread. (Javadoc needs to be
>>> updated to reflect this fact!) The first gives you the chance to run
>>> your runnable in the UI thread or branch out. The busyCursorWhile
>>> does not give you a choice but always branches into a non-UI thread.
>>>
>>> Therefore, after you call busyCursorWhile you will be running in a
>>> non-UI thread. So if you try to call it a 2nd time, within the
>>> execution of the first it will fail with illegal thread access.
>>>
>>> So now I am stuck with the weird UI conundrum. How do I get a
>>> Display so I can run in the UI thread since Displays are only given
>>> out to those already running within the UI thread?
>>>
>>> The issue is, if I am runing something with the busyCursorWhile, that
>>> puts me out of the UI thread. Then within that thread I have an
>>> occasion to access the DB again. anytime i access the db i want to
>>> open a progress dialog.
>>>
>>> I can assume that if a db access method is being called outside of
>>> the UI thread, then there is probably already a busyCursor up, but
>>> its a heck of an assumption... And anyway it makes my code a mess
>>> because running in the UI thread I get to use the busyCursor which
>>> sends my method a IProgressMonitor, but outside the UI thread This
>>> will be null, so ill have to always check for null. Im definitely
>>> tied up here!
>>>
>>>
>>> Help!
>>>
>>>
>>>
>>> Cl
>>>
>>>
>>
|
|
|
Re: All tied up with threads! [message #282744 is a reply to message #282737] |
Fri, 18 March 2005 12:07  |
Eclipse User |
|
|
|
Originally posted by: Lamont_Gilbert.rigidsoftware.com
Michael Valenta wrote:
>
> CL [dnoyeb] Gilbert wrote:
>
>> Thanks for you very informative and detailed reply. I have responded
>> within.
>>
>> Michael Valenta wrote:
>>
>>> CL,
>>>
>>> We have similar issues in the CVS plugin. What we do is use a
>>> background job to perform all our remote accessing. This means that
>>> the UI will still be live when the command is running and the user
>>> can still do things while they wait for the operation to complete.
>>> For UI updating, we have a second job that acts as an event handler.
>>> The background access job will post UI update events (directly or
>>> indirectly through model listeners) to the event handler. The event
>>> handler will then serialize the UI updates. We also batch UI updates
>>> to avoid too much UI flicker. Updates are performed by using
>>> Display#syncExec or Display#asyncExec and we use
>>> BusyIndicator#showWhile within these calls to get the busy cursor.
>>> You can have a look at the BackgroundEventHandler class in the
>>> org.eclipse.team.core pligin if your interested. It's not API but
>>> illustrates how the Team/CVS UI update event handling works.
>>>
>>
>> Unfortunately in my case, these are not job-able tasks. This is a
>> graphical program, and when you push delete, you don't want to let the
>> user then re-grab the object, only to have it deleted later on by a
>> job. You wan't the UI blocked.
>
>
>
> You may be interested to know that deletes launched from the Resource
> Navigator occur in the background (in 3.1). This is possible for two
> reasons:
>
> 1) Resources act as scheduling rules so that multiple jobs cannot modify
> the same resources (or resource tree). You can think of this as blocking
> access to the resource being deleted instead of all resources and the
> entire IDE.
>
> 2) It is fairly easy for a user to understand that any descendants of
> the selected resource will be deleted so they can expect them to
> disappear in a reasonably short time.
>
> However, this may not make sense in you context. I was only mentioning
> it as a case in point.
>
>
That is interesting. I think it can work for delete. But I dont think
so for move, and group, and other graphical operations the user expects
to be executed immediately.
already my repeated thread spawning is causing my line bendpoint
creation to snap back to original, then back again to the newly created
position after the threads finish. i can probably clean up the feedback
a bit maybe.
>>
>> I have learned though that there are different ways of blocking the
>> UI. Running in the UI 'blocks' it, but also prevents it from cleaning
>> up the interface. using busyCursorWhile, 'blocks' it, but allows it
>> to clean up the interface if/when necessary.
>>
>> The 2nd thing I want is the progress dialog. But it looks like you
>> only get 1 progress dialog. So I can't for instance, start a call in
>> busyCursorWhile that fires an event that tries to again call
>> busyCursorWhile. Well I can, if I can get back into the UI thread
>> with Display.syncexec first. Which is what I am looking at doing
>> now. This way I always get a progress dialog and/or a busy cursor.
>>
>> I think I will let each would-be caller of busyCursorWhile, provide a
>> display so I can get into the UI thread to make the call to
>> busyCursorWhile!?
>>
>>
>>> This may be a bit more work than you want to do (or may not match
>>> with your desired behavior). The root of yours specific problem is
>>> that IProgressService.run(false,false,runnable) will run in the UI
>>> thread if launched from the UI thread but
>>> IProgressService.busyCursorWhile(runnable) is never run in the UI
>>> thread. If you want your operation to run entirely in the UI thread,
>>> you can use Display#syncExec or asyncExec or use a WorkbenchJob.
>>> However, I would discourage this as it may block the UI for a long
>>> time if the operation is long running. A better approach is this:
>>>
>>> - Use busyCursorWhile (or run) to wrap the entire operation (or a Job
>>> if it coudl be run in the background)
>>> - when UI updates are needed, use Display#asyncExec or a WorkbenchJob
>>> (or Display#syncExec if synchronous updating is required).
>>> - if the UI updating could be hit from outside an operation, you can
>>> use the BusyIndicator#showWhile within the asyncExec
>>>
>>
>> Well if I can call Display#asyncExec, I might as well use a
>> WorkbenchJob right? Anytime I hit the database, I am looking to get a
>> progress dialog. You never know when that thing can crash or something.
>
>
>
> Yes, you can use WorkbenchJob instead of asyncExec. I'm a bit confused
> about the statement about getting a progress dialog each time you hit
> the database. The way I would state it is that I want a progress dialog
> up for the duration of any user triggered operations. It seems to me
> that you are trying to launch progress dialogs from various points in
> your application, some of which may be nested. I think this is a poor
> design choice. You need to understand all the points where the user
> triggered an operation and open progress dialogs there (or use
> busyCursorWhile). The IProgressMonitor obtained at that time should then
> be passed through all the subsequent operation calls and any UI updates
> can be made using syncExec, asyncExec or WorkbenchJob. If it is not
> possible to pass the IProgressMonitor through the operation than you
> have a real problem since there will be no way to provide a responsive
> UI (since, as you witnessed, you can't have multiple progress dialogs
> visible).
>
Well if its not user triggered, then it certainly can be a job. So yes,
I want progress for all user triggered actions that hit the database, or
filesystem.
And yes, there is no way to pass a progressmonitor throughout all of my
database executions. There is a disconnect between things. Especially
considering my models are architecture neutral. my application is based
on GEF. some notifications hit the db, some factory calls hit the db.
Right now I am laying down a rule that says commands will be the basis
for all database hits, so I really only need the command execution to be
in busyCursorWhile, and I will just ignore any other db calls with the
confidence that they are probably already wrapped inside one.
I am concerned though of simple redraws that come from one application
dragging across another. But I dont think the figure will ask the edit
part for more info in this case.
I may not have a problem. Just have to accept that as you said, just
wrap the topmost event which is the command. But there could be command
nesting and it would be better if the command already accepted a
progressmonitor, but you cant have everything.
>
>>
>>
>>> One warning about the UI updating. If your model does not batch
>>> change events then you may end up with many small UI updates which
>>> can have a negative impact on usability (UI flicker and
>>> unresponsiveness). It is for this reason that we sed a background job
>>> to batch UI updates.
>>>
>>> Hope this helps
>>> Michael
>>>
>>>
|
|
|
Goto Forum:
Current Time: Thu May 08 22:17:36 EDT 2025
Powered by FUDForum. Page generated in 0.23157 seconds
|