I would like to use the Fl::awake(callback) function to call functions from my main loop in an FLTK program. I am calling Fl::awake from a child thread, it returns 1 (success), but my function never gets called. I am calling Fl::wait() in a loop in the main thread. Is there any way i can troubleshoot this?
Asked
Active
Viewed 2,352 times
1 Answers
0
Code below is an example of a relatively simple FLTK 1.3 application which uses Fl::awake(callback)
. The code is from the FLTK's test directory. Just fetch the source, and you'll find numerous examples. You did not give us your code, but I assume you did not call Fl::lock()
, and later Fl::unlock()
in your thread. It is essential because you should not access widgets outside that section...
include
#if HAVE_PTHREAD || defined(WIN32)
# include <FL/Fl.H>
# include <FL/Fl_Double_Window.H>
# include <FL/Fl_Browser.H>
# include <FL/Fl_Value_Output.H>
# include <FL/fl_ask.H>
# include "threads.h"
# include <stdio.h>
# include <math.h>
Fl_Thread prime_thread;
Fl_Browser *browser1, *browser2;
Fl_Value_Output *value1, *value2;
int start2 = 3;
void magic_number_cb(void *p)
{
Fl_Value_Output *w = (Fl_Value_Output*)p;
w->labelcolor(FL_RED);
w->redraw_label();
}
void* prime_func(void* p)
{
Fl_Browser* browser = (Fl_Browser*) p;
Fl_Value_Output *value;
int n;
int step;
char proud = 0;
if (browser == browser2) {
n = start2;
start2 += 2;
step = 12;
value = value2;
} else {
n = 3;
step = 2;
value = value1;
}
// very simple prime number calculator !
//
// The return at the end of this function can never be reached and thus
// will generate a warning with some compilers, however we need to have
// a return statement or other compilers will complain there is no return
// statement. To avoid warnings on all compilers, we fool the smart ones
// into beleiving that there is a chance that we reach the end by testing
// n>=0, knowing that logically, n will never be negative in this context.
if (n>=0) for (;;) {
int pp;
int hn = (int)sqrt((double)n);
for (pp=3; pp<=hn; pp+=2) if ( n%pp == 0 ) break;
if (pp >= hn) {
char s[128];
sprintf(s, "%d", n);
// Obtain a lock before we access the browser widget...
Fl::lock();
browser->add(s);
browser->bottomline(browser->size());
if (n > value->value()) value->value(n);
n += step;
// Release the lock...
Fl::unlock();
// Send a message to the main thread, at which point it will
// process any pending redraws for our browser widget. The
// message we pass here isn't used for anything, so we could also
// just pass NULL.
Fl::awake(p);
if (n>10000 && !proud) {
proud = 1;
Fl::awake(magic_number_cb, value);
}
} else {
// This should not be necessary since "n" and "step" are local variables,
// however it appears that at least MacOS X has some threading issues
// that cause semi-random corruption of the (stack) variables.
Fl::lock();
n += step;
Fl::unlock();
}
}
return 0L;
}
int main(int argc, char **argv)
{
Fl_Double_Window* w = new Fl_Double_Window(200, 200, "Single Thread");
browser1 = new Fl_Browser(0, 0, 200, 175);
w->resizable(browser1);
value1 = new Fl_Value_Output(100, 175, 200, 25, "Max Prime:");
w->end();
w->show(argc, argv);
w = new Fl_Double_Window(200, 200, "Six Threads");
browser2 = new Fl_Browser(0, 0, 200, 175);
w->resizable(browser2);
value2 = new Fl_Value_Output(100, 175, 200, 25, "Max Prime:");
w->end();
w->show();
browser1->add("Prime numbers:");
browser2->add("Prime numbers:");
// Enable multi-thread support by locking from the main
// thread. Fl::wait() and Fl::run() call Fl::unlock() and
// Fl::lock() as needed to release control to the child threads
// when it is safe to do so...
Fl::lock();
// Start threads...
// One thread displaying in one browser
fl_create_thread(prime_thread, prime_func, browser1);
// Several threads displaying in another browser
fl_create_thread(prime_thread, prime_func, browser2);
fl_create_thread(prime_thread, prime_func, browser2);
fl_create_thread(prime_thread, prime_func, browser2);
fl_create_thread(prime_thread, prime_func, browser2);
fl_create_thread(prime_thread, prime_func, browser2);
fl_create_thread(prime_thread, prime_func, browser2);
Fl::run();
return 0;
}
#else
# include <FL/fl_ask.H>
int main() {
fl_alert("Sorry, threading not supported on this platform!");
}
#endif // HAVE_PTHREAD || WIN32

DejanLekic
- 18,787
- 4
- 46
- 77
-
I actually don't call lock and unlock because i don't access widgets outside of the main thread. I was just using awake as a signalling mechanism. The lock call in main worked to fix it though, thanks for pointing me in the right direction. – Woodrow Douglass Nov 29 '11 at 18:37
-
Note: this code lets a "processing" thread run in the background while letting the GUI still be responsive, but this implementation can let the processing thread get hung by a non-responsive GUI. For example, if you resize the window and just drag the mouse around while resizing, the calculation of the prime numbers will stop until you stop creating GUI events. Calling Fl::awake() doesn't avoid the problem because you still need a lock/unlock to make the main thread notice the awake() event. So, if you want your "processing" thread to be immune from the GUI, you can't make any FLTK calls. – cape1232 Nov 13 '13 at 21:16
-
Slightly unrelated, but let me add: **It is extremely important to call `Fl::lock()` in the main function.** I was trying to write a program without that call, and it did not work due to contention. – bcdan Aug 18 '17 at 21:20