I don't really think this is what Paul wanted, and it turned out longer
than I'd intended.

So... Sorry in advance for the noise...

//////////////////////////////////////////////////////
// Threading demo
// fltk-config --compile simple-thread-demo.cxx
//

#include <stdlib.h>
#include <unistd.h>
#include <math.h>

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Value_Output.H>

#ifdef WIN32
#  include <windows.h>
#  include <process.h>
#  define THREAD HANDLE
#  define wait_here(x)  Sleep(x)
#  define SCHED_YIELD   Sleep(0)
#else /* for *nix and OSX */
#  include <pthread.h>
#  include <sched.h>  // maybe necessary for sched_yield ?
#  define THREAD pthread_t
#  define PTHREAD_WRAPPER 1
#  define wait_here(x)  usleep((x)*1000)
#  define SCHED_YIELD   sched_yield()
#endif

#define GUI_REFRESH_THD 987

static Fl_Double_Window *main_win=(Fl_Double_Window *)0;

static Fl_Button *work_0=(Fl_Button *)0;
static Fl_Button *work_1=(Fl_Button *)0;
static Fl_Button *yeild_bt=(Fl_Button *)0;
static Fl_Button *reduced_update=(Fl_Button *)0;
static Fl_Button *quit_bt=(Fl_Button *)0;

static Fl_Value_Output *out[2];

/* Should the worker threads yield periodically or not? */
static int use_yield = 0;
// use this to make the GUI update less often
static int reduce_refresh_rate = 0;

// Use to signal child threads to terminate... It's a cheap IPC hack...
static int keep_running = -1;
static int thread_active[2]; // one per worker...

/* Wrapper to start the worker thread */
THREAD make_thread (void (*task)(void *), void *arg)
{
     int res;
#ifdef WIN32
     res = _beginthread(task, 0, arg);
     return (THREAD)res;
#else // linux, OSX and other unix systems
     pthread_t thread;
     res = pthread_create(&thread, NULL, (void*)task, arg);
     if (res == 0)
         return thread;
     else
         return (THREAD)0;
#endif
}

// Send the updated value to the GUI - this may be sloooowwwww....
static void display_value(int id, double val) {
        Fl::lock();      // avoid conflicting calls
        out[id]->value(val); // update the GUI value
        Fl::awake();     // tell the GUI thread that something maybe
changed
        Fl::unlock();    // allow other threads to access FLTK again
}

/* This is the worker thread - it chews up ALL the CPU that it is given
*/
void test_thread(void *arg)
{
        int id = (int)arg;
        double dr = 0.0;

        while ((keep_running) && (thread_active[id]))
        {
                // do something slow here
                for (int j = 0; j < 6789; j++)
                {
                        double d = (double)(j+1);
                        dr = log(d);
                        if(reduce_refresh_rate == 0){
                                // update on every iteration - very
SLOW!
                                // If you update on every iteration,
then what tends
                                // to happen is that the CPU the GUI
thread is running
                                // on gets pegged, and that become the
rate determining
                                // stage.
                                // So, usually it is better to only
update the GUI
                                // periodically...
                                display_value(id, dr);
                        }
                        else {
                                static int iter = GUI_REFRESH_THD;
                                if(iter < 0) {
                                        // update periodically - less
slow!
                                        display_value(id, dr);
                                        iter = GUI_REFRESH_THD;
                                }
                                iter--;
                        }
                }
                /* On some systems, particularly single-cpu ones,
throwing in the
                 * occasional voluntary worker yield will make the GUI
thread seem
                 * more responsive. */
                if(use_yield) SCHED_YIELD;
        }
        return;
}

static void do_start(int state, int id) {
        if(state) { // start the worker thread
                thread_active[id] = 1;
                make_thread(test_thread, (void *)id);
        }
        else { // terminate the worker thread
                thread_active[id] = 0; // the worker will see this and
exit
        }
}

static void cb_work_0(Fl_Button* o, void*) {
        int state = o->value();
        do_start(state, 0);
}

static void cb_work_1(Fl_Button* o, void*) {
        int state = o->value();
        do_start(state, 1);
}

static void cb_yeild_bt(Fl_Button* o, void*) {
        use_yield = (int)o->value();
}

static void cb_reduce_bt(Fl_Button* o, void*) {
        reduce_refresh_rate = (int)o->value();
}

static void cb_quit_bt(Fl_Button*, void*) {
        main_win->hide(); // close the GUI
        keep_running = 0; // ask the workers to expire
}

int main(int argc, char **argv) {
        // ensure thread support is enabled...
        Fl::lock();

        // now build the GUI
        main_win = new Fl_Double_Window(322, 209, "Thread control");
        main_win->begin();

        work_0 = new Fl_Button(25, 18, 70, 27, "Worker 0");
        work_0->tooltip("Start woker thread 0");
        work_0->type(FL_TOGGLE_BUTTON);
        work_0->callback((Fl_Callback*)cb_work_0);

        work_1 = new Fl_Button(135, 18, 70, 27, "Worker 1");
        work_1->tooltip("Start woker thread 1");
        work_1->type(FL_TOGGLE_BUTTON);
        work_1->callback((Fl_Callback*)cb_work_1);

        out[0] = new Fl_Value_Output(25, 58, 70, 24);
        out[1] = new Fl_Value_Output(135, 58, 70, 24);

        yeild_bt = new Fl_Button(25, 163, 70, 27, "With Yeild");
        yeild_bt->tooltip("Cause worker threads to yeild periodically");
        yeild_bt->type(FL_TOGGLE_BUTTON);
        yeild_bt->callback((Fl_Callback*)cb_yeild_bt);

        reduced_update = new Fl_Button(135, 163, 80, 27, "Update Less");
        reduced_update->tooltip("Update the GUI less often");
        reduced_update->type(FL_TOGGLE_BUTTON);
        reduced_update->callback((Fl_Callback*)cb_reduce_bt);

        quit_bt = new Fl_Button(240, 163, 70, 27, "Quit");
        quit_bt->tooltip("Doh!");
        quit_bt->callback((Fl_Callback*)cb_quit_bt);

        main_win->end();

        // show the GUI
        main_win->show(argc, argv);

        // start the event loop
        return Fl::run();
}

/* end of file */


SELEX Galileo 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.
********************************************************************

_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk

Reply via email to