> Since your calculation is in a separate program being read
> through popen(), your FLTK app is likely blocking during
> the fread()/fgets() operations.
>
> So unless you can make those operations non-blocking,
> you'll need to use a thread to manage the
> popen()/reading/pclose()
> to ensure your app and FLTK doesn't block.
> But if you're using Windows, don't use the above two approaches.
> The best way to go is create a thread to handle the
> popen()+read+close,
> and have the main thread to watch for data as it comes in using
> either the Fl::check() approach to poll for new data, or create
> an Fl::add_timeout() that watches for data 4 or 5 times
> per second.
> I don't have an example for that ATM, but if I find some time,
> I can maybe supply one.
If it is any use, attached is a crude demo I did a while back, that
starts threads to do the work. Uses a crude wrapper "make_thread()" for
pthread_create() or _beginthread() so that it works cross-platform, and
the comms between the main GUI thread and the workers is done via
globals (which is probably not the most sophisticated IPC we could come
up with.)
Nonetheless, it works OK for the purposes of the demo. Sorry the code is
not better commented, though, so it may not be obvious quite what it is
really doing!
---------------
/* demo of executing time-consuming tasks in multiple threads */
// fltk-config --compile threads-demo.cxx
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Value_Input.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Progress.H>
#ifdef WIN32
# include <windows.h>
# include <process.h>
# define THREAD HANDLE
#else
# include <pthread.h>
# define THREAD pthread_t
#endif
// info to communicate with the worker thread
typedef struct _filt_info {
int running;
double p1;
double p2;
int progress;
} filt_info;
// function to update progress bar in GUI
static void progress_timer(void *v);
// A notional worker thread task...
static void worker_thread(void *v);
// Helper function to spawn a worker thread
void make_thread (void (*task)(void *), void *arg)
{
int res;
#ifdef WIN32
res = _beginthread(task, 0, arg);
#else
pthread_t thread;
// this casts the worker task from (void) to (void*) and is a
bit duff!
res = pthread_create(&thread, NULL, (void*(*)(void*))&task,
arg);
#endif
} // make_thread
class FiltWin : public Fl_Double_Window {
void _FiltWin();
public:
FiltWin(int W, int H, const char *L = 0);
// these ought not be public...
Fl_Value_Input *p1;
Fl_Value_Input *p2;
Fl_Button *start_bt;
Fl_Button *cancel_bt;
Fl_Progress *progress;
void init_state(void);
// Hacktastic IPC via global vars... This needs done better!
// mark as volatile to ensure both threads see changes
volatile filt_info filter_info;
private:
void cb_start_bt_i(Fl_Button*, void*);
static void cb_start_bt(Fl_Button*, void*);
void cb_cancel_bt_i(Fl_Button*, void*);
static void cb_cancel_bt(Fl_Button*, void*);
};
void FiltWin::init_state(void) {
filter_info.progress = 0;
filter_info.running = 0;
cancel_bt->deactivate();
start_bt->activate();
} // init_state
void FiltWin::cb_start_bt_i(Fl_Button* o, void* v) {
// start bt callback;
filter_info.progress = 0;
filter_info.p1 = p1->value();
filter_info.p2 = p2->value();
filter_info.running = -1;
// enable the cancel button now...
cancel_bt->activate();
start_bt->deactivate();
// start the worker thread
make_thread(worker_thread, (void*)&filter_info);
// start the progress_bar timeout
Fl::add_timeout(0.1, progress_timer, (void*)this);
}
void FiltWin::cb_start_bt(Fl_Button* o, void* v) {
((FiltWin*)(o->parent()))->cb_start_bt_i(o,v);
}
void FiltWin::cb_cancel_bt_i(Fl_Button* o, void* v) {
// cancel bt callback;
filter_info.running = 0;
hide();
}
void FiltWin::cb_cancel_bt(Fl_Button* o, void* v) {
((FiltWin*)(o->parent()))->cb_cancel_bt_i(o,v);
}
FiltWin::FiltWin(int W, int H, const char *L)
: Fl_Double_Window(0, 0, W, H, L) {
clear_flag(16);
_FiltWin();
}
void FiltWin::_FiltWin() {
p1 = new Fl_Value_Input(30, 26, 40, 24, "Param 1");
p1->align(FL_ALIGN_RIGHT);
p2 = new Fl_Value_Input(30, 56, 40, 24, "Param 2");
p2->align(FL_ALIGN_RIGHT);
start_bt = new Fl_Button(25, 215, 65, 35, "Start");
start_bt->callback((Fl_Callback*)cb_start_bt);
cancel_bt = new Fl_Button(110, 215, 65, 35, "Cancel");
cancel_bt->callback((Fl_Callback*)cb_cancel_bt);
cancel_bt->deactivate();
progress = new Fl_Progress(36, 130, 205, 26, "Progress");
progress->selection_color(FL_BLUE);
// set_modal(); // filter windows can be modal if desired
end();
}
static Fl_Double_Window *main_win=(Fl_Double_Window *)0;
static Fl_Button *filt_bt1=(Fl_Button *)0;
static Fl_Button *filt_b2=(Fl_Button *)0;
static Fl_Button *exit_bt=(Fl_Button *)0;
static FiltWin *fw1=(FiltWin *)0;
static FiltWin *fw2=(FiltWin *)0;
static void cb_filt_bt1(Fl_Button*, void*) {
// filter 1 callback;
fw1->init_state();
fw1->show();
}
static void cb_filt_b2(Fl_Button*, void*) {
// filter 2 callback;
fw2->init_state();
fw2->show();
}
static void cb_exit_bt(Fl_Button*, void*) {
// exit callback
// cancel worker threads
fw1->filter_info.running = 0;
fw2->filter_info.running = 0;
// close the application windows
fw1->hide();
fw2->hide();
main_win->hide();
}
/* This timeout allows the progress bar to update without the worker
* thread accessing the GUI directly */
static void progress_timer(void *v){
FiltWin *w = (FiltWin*)v;
double prog = (double)w->filter_info.progress;
w->progress->value(prog);
if(w->filter_info.progress >= 100){
w->cancel_bt->deactivate();
w->start_bt->activate();
}
Fl::repeat_timeout(0.1, progress_timer, (void*)w);
}
// Test thread: this thread will spin, chewing up as much CPU as it can
get
static void worker_thread(void *v){
volatile filt_info *state = (filt_info *)v;
int iters = 0;
// thread runs until "running" goes to zero or progress is 100%
while((state->running == -1) && (state->progress < 100)){
iters ++;
if (iters > 99999999){
iters = 0;
state->progress ++;
}
}
} // worker_thread
int main(int argc, char **argv) {
main_win = new Fl_Double_Window(261, 209, "Main Window");
filt_bt1 = new Fl_Button(25, 25, 75, 40, "Filter 1");
filt_bt1->callback((Fl_Callback*)cb_filt_bt1);
filt_b2 = new Fl_Button(25, 80, 75, 40, "Filter 2");
filt_b2->callback((Fl_Callback*)cb_filt_b2);
exit_bt = new Fl_Button(180, 155, 75, 40, "Exit");
exit_bt->callback((Fl_Callback*)cb_exit_bt);
main_win->end();
main_win->callback((Fl_Callback*)cb_exit_bt);
fw1 = new FiltWin(280, 280, "Filter 1");
fw1->end();
fw2 = new FiltWin(280, 280, "Filter 2");
fw2->end();
main_win->show(argc, argv);
return Fl::run();
}
/* end of file */
---------------
Ian
SELEX Sensors and Airborne Systems Limited
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.
********************************************************************
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk