[Tizen Application-dev] Update Progressbar Native Download API

Carsten Haitzler (The Rasterman) tizen at rasterman.com
Wed May 11 23:59:44 GMT 2016


On Wed, 11 May 2016 15:15:48 +0700 leonardus ardyandhita <leo4rdyand at gmail.com>
said:

> Hi, I need to update progress bar on my UI during download progress using
> Native Download API. I have set callback *download_set_progress_cb *to get
> the progress update. But, when I set value my progress bar (UI) inside the
> progress callback, my progress bar sometimes not updated even force close
> the app.
> 
> Something that I know progress bar run on mainloop thread, but download API
> run on other thread. My question is how to send data to mainloop thread
> from that download API progress callback ? Thanks :)

i'm going to put this plainly as i'm currently annoyed that advice to "not do
this" was not listened to... years ago. advice of "do not call callbacks FROM a
THREAD". it adds complexity (it REQUIRES app developers to add locks to all the
data they may access in cb's directly or indirectly in their app), it's
unexpected, and it's just in general poor design.

you should only call callbacks from a thread is very rarely. it should be a
very rare day that it's needed. *IF* it's done it should be documented clearly
in big red bold blinking text (well not literally but the point is a developer
shouldn't have to figure this out. it should be clear).

there are rare and good reasons to do this. a download cb is NOT one of them.

now i've gotten the evisceration out of the way (this is example #2 just
this week of cb's from threads in tizen native api, and i want this lesson to
stick so it's not repeated)... the solution is not that hard.

yes. the ui belongs to the mainloop. the whole mainloop is design to sleep,
wait for input or events or timeouts, wake up, handle them, change the state of
the world, then when about to go back to sleep again, re-evaluate the ui and
rendering and update things. this way updates are done when all changes are
FINISHED for that round of events, which keeps ui consistent in terms of state.

you get app crashes because you access and modify ui data/objects from a
thread, which you may not do. also the mainloop has no idea what you just did.
it didn't wake up and re-evaluate. thus why it doesn't update.

there are many many many ways to do this. the SIMPLEST would be in your
callback to, if your cb looks like this:

mycb() {
  some code();
  ui update code();
}

then change it to be:

mycb() {
  some code();
  ecore_main_loop_begin();
  ui update code();
  ecore_main_loop_end();
}

upstream efl has a whole host of docs/examples of how to use threads with efl.

https://docs.enlightenment.org/elementary/current/threading.html

the above would be example 1. the begin() will block and wait for the mainloop
to go to sleep and synchronise at a specific point. it will then pretend your
thread is the  mainloop for now. then end() will release the mainloop waking it
up again. it isn't high performance, but its dead-simple. you could get a few
hundred maybe a few thousand of these in per second without too much trouble.
but it does involve back and forth from thread to thread, syncrhonising etc.
etc. and every time you do a new begin it has to wait for mainloop to come
around to the same point again as it may be busy with other things.

there are other ways like:

https://docs.enlightenment.org/elementary/current/efl_thread_3.html

specifically ecore_main_loop_thread_safe_call_async() 5that will call a
specific function from the mainloop passing in the specific void * data param
- allocate a struct and stuff relevant data in here for the call then free it
inside the func when called. nothing blocks here.

anyway. there you go. i'm really sorry you had to hit this pain. it should
never have happened (as above in my evisceration). you shouldn't have to deal
with this.

reality is that making the ui work from multipel threads is a can of worms of
pain. how do you then know when updates are done? what happens when from a
thread you are modifying the ui bit by bit and the mainloop is also now awake?
you end up with a ui partly configured/changed that's rendered. not to mention
that every single api call and so on needs a lock and unlock now... just in
case someone uses them from threads. this is why generally ui's are owned by a
specific thread. you need to modify ui from that thread context. marshall back
info to that thread - like above. it's much better if the native api does this
for you without you needing to know about it. :)

-- 
Carsten Haitzler (The Rasterman) <tizen at rasterman.com>


More information about the Application-dev mailing list