Here are the results I ran your sample program on one core and dualcore
machines:
One Core:
run with Update Less: Worker0: on average takes 3750 miliseconds
Worker0 + Worker1: on average takes 5980 ms
Dual Core:
run with Update Less: Worker0: on average takes 4000 ms
Worker0 + Worker1: on average takes 7532 ms.
I looked at the task manager performance when running on dualcore, the two
cores were not processing simultaneously.
I would like to take the advantage of the dualcore. What is the approach I
should take to program one core doing calculation while the other core
displaying results?
Thanks,
//////////////////////////////////////////////////////
// Threading demo
// fltk-config --compile simple-thread-demo.cxx
//
#include <stdlib.h>
//#include <unistd.h>
#include <math.h>
#include <time.h>
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Value_Output.H>
#include <FL/fl_message.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
#define GUI_REFRESH_THD 493
clock_t startTime0, endTime0, startTime1, endTime1;
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
maybechanged
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;
int ii = 2000;
if (id == 0)
startTime0 = clock();
else
startTime1 = clock();
while ((keep_running) && (thread_active[id]) && ii > 0)
{
// 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 - verySLOW!
// If you update on every iteration,then what
tends
// to happen is that the CPU the GUIthread is
running
// on gets pegged, and that become therate
determining
// stage.
// So, usually it is better to onlyupdate 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;
ii--;
}
if (id == 0)
{
endTime0 = clock();
dr = (double)(endTime0 - startTime0);
display_value(id, dr);
}
else
{
/*endTime1 = clock();
dr = (double)(endTime1 - startTime1);
display_value(id, dr);*/
//display total time running on both threads
dr = (double)(endTime1 - startTime0);
display_value(id, dr);
}
return;
} // END of test_thread(void *arg)
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();
// char msg[1000];
// sprintf(msg,"GUI_REFRESH_THD = %d",GUI_REFRESH_THD);
// fl_message(msg);
// show the GUI
main_win->show(argc, argv);
// start the event loop
return Fl::run();
}
/* end of file */
// SELEX Galileo LtdRegistered Office:
// Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
// A company registered in England & Wales. Company no. 02426132
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk