Improve test/threads demo program (backported from 1.5)
- use Fl_Terminal instead of Fl_Browser for prime display - add Fl::lock()/Fl::unlock() at thread initialization - format "Max Prime" output as integer number - use a fixed font for better readability - close all windows when the user closes one of them - use standard background and text colors Note: This commit is a compromise. The version in FLTK 1.5 uses std::vector<> and can't be fully backported to 1.4.
This commit is contained in:
parent
a5d2d19a23
commit
75f3bdfa55
159
test/threads.cxx
159
test/threads.cxx
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Threading example program for the Fast Light Tool Kit (FLTK).
|
||||
//
|
||||
// Copyright 1998-2018 by Bill Spitzak and others.
|
||||
// Copyright 1998-2025 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
@ -19,8 +19,8 @@
|
||||
#if defined(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_Terminal.H>
|
||||
# include <FL/Fl_Output.H>
|
||||
# include <FL/fl_ask.H>
|
||||
# include "threads.h"
|
||||
# include <stdio.h>
|
||||
@ -28,34 +28,39 @@
|
||||
|
||||
Fl_Thread prime_thread;
|
||||
|
||||
Fl_Browser *browser1, *browser2;
|
||||
Fl_Value_Output *value1, *value2;
|
||||
Fl_Terminal *tty1, *tty2;
|
||||
Fl_Output *value1, *value2;
|
||||
int start2 = 3;
|
||||
|
||||
void magic_number_cb(void *p)
|
||||
{
|
||||
Fl_Value_Output *w = (Fl_Value_Output*)p;
|
||||
void magic_number_cb(void *p) {
|
||||
Fl_Output *w = (Fl_Output*)p;
|
||||
w->labelcolor(FL_RED);
|
||||
w->redraw_label();
|
||||
// if (w == value1) Fl::hide_all_windows(); // TEST: terminate early to measure time
|
||||
}
|
||||
|
||||
extern "C" void* prime_func(void* p)
|
||||
{
|
||||
Fl_Browser* browser = (Fl_Browser*) p;
|
||||
Fl_Value_Output *value;
|
||||
int n;
|
||||
extern "C" void* prime_func(void* p) {
|
||||
Fl_Terminal* terminal = (Fl_Terminal*)p;
|
||||
Fl_Output *value;
|
||||
unsigned long n;
|
||||
unsigned long max_value = 0;
|
||||
int step;
|
||||
char proud = 0;
|
||||
char maxbuf[32];
|
||||
|
||||
if (browser == browser2) {
|
||||
n = start2;
|
||||
// initialize thread variables
|
||||
|
||||
if (terminal == tty2) { // multiple threads
|
||||
Fl::lock(); // lock to prevent race condition on `start2`
|
||||
n = start2;
|
||||
start2 += 2;
|
||||
step = 12;
|
||||
value = value2;
|
||||
} else {
|
||||
n = 3;
|
||||
step = 2;
|
||||
value = value1;
|
||||
Fl::unlock();
|
||||
step = 12;
|
||||
value = value2;
|
||||
} else { // single thread
|
||||
n = 3;
|
||||
step = 2;
|
||||
value = value1;
|
||||
}
|
||||
|
||||
// very simple prime number calculator !
|
||||
@ -63,35 +68,45 @@ extern "C" void* prime_func(void* p)
|
||||
// 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 (;;) {
|
||||
// statement. To avoid warnings on all compilers, we fool the smart ones into
|
||||
// believing that there is a chance that we reach the end by testing n > 0,
|
||||
// knowing that logically, n will never be less than 3 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];
|
||||
snprintf(s, 128, "%d", n);
|
||||
for (pp = 3; pp <= hn; pp += 2) {
|
||||
if (n % pp == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pp > hn) { // n is a prime
|
||||
|
||||
// Obtain a lock before we access the terminal widget...
|
||||
// Note: locking the GUI for each prime number is not recommended.
|
||||
// A better (more efficient) solution has been implemented in FLTK 1.5
|
||||
|
||||
// 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;
|
||||
terminal->printf("prime: %10u\n", n);
|
||||
if (n > max_value) {
|
||||
max_value = n;
|
||||
snprintf(maxbuf, sizeof(maxbuf), "%9lu", max_value);
|
||||
value->value(maxbuf);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Send a message to the main thread, at which point it will process
|
||||
// any pending redraws for our terminal widget.
|
||||
|
||||
Fl::awake();
|
||||
|
||||
n += step;
|
||||
|
||||
if (n > 2 * 1000 * 1000 && !proud) {
|
||||
proud = 1;
|
||||
Fl::awake(magic_number_cb, value);
|
||||
}
|
||||
@ -107,42 +122,64 @@ extern "C" void* prime_func(void* p)
|
||||
return 0L;
|
||||
}
|
||||
|
||||
// close all windows when the user closes one of the windows
|
||||
|
||||
void close_cb(Fl_Widget *w, void *v) {
|
||||
Fl::hide_all_windows();
|
||||
printf("Max prime number with 1 thread : %s\n", value1->value());
|
||||
printf("Max prime number with 6 threads: %s\n", value2->value());
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// First window: single thread
|
||||
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:");
|
||||
tty1 = new Fl_Terminal(0, 0, 200, 175);
|
||||
tty1->color(FL_BACKGROUND2_COLOR);
|
||||
tty1->textcolor(FL_FOREGROUND_COLOR);
|
||||
w->resizable(tty1);
|
||||
value1 = new Fl_Output(100, 175, 98, 23, "Max Prime:");
|
||||
value1->textfont(FL_COURIER);
|
||||
w->callback(close_cb);
|
||||
w->end();
|
||||
w->show(argc, argv);
|
||||
|
||||
// Second window: multiple threads
|
||||
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:");
|
||||
tty2 = new Fl_Terminal(0, 0, 200, 175);
|
||||
tty2->color(FL_BACKGROUND2_COLOR);
|
||||
tty2->textcolor(FL_FOREGROUND_COLOR);
|
||||
w->resizable(tty2);
|
||||
value2 = new Fl_Output(100, 175, 98, 23, "Max Prime:");
|
||||
value2->textfont(FL_COURIER);
|
||||
w->callback(close_cb);
|
||||
w->end();
|
||||
w->show();
|
||||
|
||||
browser1->add("Prime numbers:");
|
||||
browser2->add("Prime numbers:");
|
||||
tty1->printf("Prime numbers:\n");
|
||||
tty2->printf("Prime numbers:\n");
|
||||
|
||||
// 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...
|
||||
|
||||
// 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);
|
||||
// One thread displaying in one terminal
|
||||
|
||||
// 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_create_thread(prime_thread, prime_func, tty1);
|
||||
|
||||
// Six threads displaying in another terminal
|
||||
|
||||
fl_create_thread(prime_thread, prime_func, tty2);
|
||||
fl_create_thread(prime_thread, prime_func, tty2);
|
||||
fl_create_thread(prime_thread, prime_func, tty2);
|
||||
fl_create_thread(prime_thread, prime_func, tty2);
|
||||
fl_create_thread(prime_thread, prime_func, tty2);
|
||||
fl_create_thread(prime_thread, prime_func, tty2);
|
||||
|
||||
Fl::run();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user