Discussion:
Correct way to fire graphics updates from abackground thread
Albrecht Schlosser
2013-03-18 10:12:05 UTC
Permalink
Hi all,
just to have confirmation of what I am doing.
My app is multithreaded ; the main() loop and some other working threads, receiving / sending data and doing calculations.
The question: what is the correct way to fire a graphics update from a thread ?
.....
static int fd_refresh[2];
.....
pipe(fd_refresh);
SetNonblocking(fd_refresh[0]);
SetNonblocking(fd_refresh[1]);
Fl::add_fd(fd_refresh[0], Do_refresh_callback, NULL);
.....
#define CMD_REFRESH 0
.....
static void Do_refresh_callback(int fd, void *data)
{
unsigned int val;
while(read(fd, &val, sizeof(val)) > 0)
{
switch(val)
{
// HERE I can draw to screen !
<nitpick on>
To be precise: no, you can't!
</nitpick>

You can do widget updates and call redraw(), but you must not
call draw() methods directly from a callback. See also below.
break;
.....
}
}
.....
}
- A thread receives data and wants to update a drawing. It cannot do it directly,
so it writes to fd_refresh[1] an integer which values represent what I want to do
(full redraw(), partial updates, etc.) .
Fltk then will call Do_refresh_callback and there I will be safe drawing anything.
Is this sequence correct ?
Now it's working without (apparent) problems.
AFAICT this is okay, so long as you don't call draw() directly,
as I wrote above.

However, using Fl::add_fd() with a pipe is not portable. IIRC you're
using an embedded Linux platform, so this may not be a problem for you.

But there are maybe more simple and portable ways using Fl::lock() and
Fl::awake() to send messages from a thread to the FLTK main loop to do
what you need. You can read more about this in the chapter "Advanced
FLTK" in the docs.

http://www.fltk.org/doc-1.3/advanced.html

Others will probably chime in and tell you more about programming with
threads and FLTK.


Albrecht
MacArthur, Ian (Selex ES, UK)
2013-03-18 10:54:11 UTC
Permalink
The question: what is the correct way to fire a graphics update from
a thread ?
Others will probably chime in and tell you more about programming with
threads and FLTK.
Ah... That quite possibly means me then...

OK, at a high level, it goes something like this:

Firstly, a caveat: Rendering to the display device from any thread other than the "main" thread is not robust (may work on some systems, will fail in horrible, hard to debug ways, on others, so do not do that.)

Instead, all drawing is done from the "main" thread. In particular, note that creating/deleting/hiding/showing windows *has* to be done by the "main" thread.

However, if you create your widgets in the "main" thread, you can alter them from other threads quite safely, if you use the fltk locking methods. You can signal updates between threads using Fl::awake(); there's no need to get fancy with pipe's and so forth (fltk is handling that internally) and it is more portable.

Here's a simple recipe for this:

- in the "main" thread, before you create any windows, call Fl::lock(); *just once* to enable thread support. (Do not do any more locking/unlocking in the main thread, let fltk manage that for you.)

- in a worker thread, if you want to update a widget, do:

Fl::lock();
my_widget->change_this();
my_other_widget->change_that(value);
etc.;
Fl::unlock();
Fl::awake();

And that should update the widgets in a thread-safe way, then flag the main thread to manage the redraw sequence.

Note that Fl::awake can also be passed a callback function - the "main" thread will then execute that callback in its context, allowing the worker threads to do some operations that would not otherwise be allowed (e.g. you may be able to use this to create new windows under the control of a child thread, since the actual creation will occur in the context of the "main" thread.)

However, that is often not necessary, the simple case I outlined above covers a lot of use cases.



Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************
Edzard Egberts
2013-03-18 12:29:24 UTC
Permalink
My app is multithreaded ; the main() loop and some other working
threads, receiving / sending data and doing calculations.
The question: what is the correct way to fire a graphics update from
a thread ?
We see, there are several correct ways. For measurements made by threads
I'm using a list for buffering data. Some pseudocode:

struct point {
int x;
int y;
point(int px= 0, int py= 0): x(px), y(py) {}
};

std::list< point > Buf

critical_section CS;

void Incoming(int x, int y)
{ // Buffering incoming data:
CS.lock();
Buf.push_back(point(x, y));
CS.unlock();
}

std::list< point > Outgoing()
{ // Calling buffered data
std::list< point > OBuf
CS.lock();
OBuf.swap(Buf);
CS.unlock();
return OBuf;
}

while(!OBuf.empty())
{ // Read points in original sequence:
Use_Point(OBuf.front().x, OBuf.front().y);
OBuf.pop_front();
}

So data are coming in in threads speed and GUI is updated in "user
speed", evaluating several data at once. This basic mechanism I'm using
with several objects, from points to system states.

Loading...