summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael R Sweet <michael.r.sweet@gmail.com>2007-02-12 16:00:28 +0000
committerMichael R Sweet <michael.r.sweet@gmail.com>2007-02-12 16:00:28 +0000
commitb5d637a4cdfa54a1c8843f03733f0b91fb9c4f12 (patch)
tree37996cf0463878e161cfb8aef5ca7f109bde0e65
parentded0bf043271d3251c66b6417f77b30d77377d64 (diff)
Clean up threads example, use new set_awake_cb().
Update chapter 10 of the documentation to provide cleaner examples. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@5691 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
-rw-r--r--documentation/advanced.html51
-rw-r--r--test/threads.cxx47
2 files changed, 70 insertions, 28 deletions
diff --git a/documentation/advanced.html b/documentation/advanced.html
index 51ea1895b..dea29c41d 100644
--- a/documentation/advanced.html
+++ b/documentation/advanced.html
@@ -15,33 +15,52 @@ that will help you to get the most out of FLTK.</P>
<P>To use the locking mechanism, FLTK must be compiled with <tt>--enable-threads</tt> set during the <tt>configure</tt> process. IDE-based versions of FLTK are automatically compiled with locking enabled if possible.
-<P>In <TT>main()</TT>, call <TT>Fl::lock()</TT> before <TT>Fl::run()</TT> to start the runtime multithreading support for your program. All callbacks and derived functions like <tt>handle()</tt> and <tt>draw()</tt> will now be properly locked.
+<P>In <TT>main()</TT>, call <a href="Fl.html#Fl.lock"><TT>Fl::lock()</TT></A> before <A HREF="Fl.html#Fl.run"><TT>Fl::run()</TT></A> or <A HREF="Fl.html#Fl.wait"><TT>Fl::wait()</TT></A> to start the runtime multithreading support for your program. All callbacks and derived functions like <tt>handle()</tt> and <tt>draw()</tt> will now be properly locked:</P>
<pre>
- main() {
- <a href="Fl.html#Fl.lock">Fl::lock()</a>;
- /* run thread */
- while(Fl::wait() > 0) {
- if(<a href="Fl.html#Fl.thread_message">Fl::thread_message()</a>) {
- /* process your data */
+ int main() {
+ Fl::lock();
+ /* run thread */
+ while (Fl::wait() > 0) {
+ if (Fl::thread_message()) {
+ /* process your data */
+ }
}
}
- }
-
</pre>
<P>You can now start as many threads as you like. From within
a thread (other than the main thread) FLTK calls must be wrapped
-in the following code:
+with calls to <a href="Fl.html#Fl.lock"><tt>Fl::lock()</tt></a> and <a href="Fl.html#Fl.unlock"><tt>Fl::unlock()</tt></a>:
<pre>
- <a href="Fl.html#Fl.lock">Fl::lock()</a>; // avoid conflicting calls
- ... // your code here
- <a href="Fl.html#Fl.unlock">Fl::unlock()</a>; // allow other threads to access FLTK again
- <a href="Fl.html#Fl.awake">Fl::awake(msg)</a>; // tells FLTK that another thread has made changes
+ Fl::lock(); // avoid conflicting calls
+ ... // your code here
+ Fl::unlock(); // allow other threads to access FLTK again
+</pre>
+
+<p>You can send messages from child threads to the main thread using <a href="Fl.html#Fl.awake"><tt>Fl::awake(msg)</tt></a>:</p>
+<pre>
+ void *msg; // "msg" is a pointer to your message
+ Fl::awake(msg); // send "msg" to main thread
</pre>
+<p>These messages can be read by the main thread using <A HREF="Fl.html#Fl.thread_message"><TT>Fl::thread_message()</TT></A> or by registering a message callback with <A HREF="Fl.html#Fl.set_awake_cb"><TT>Fl::set_awake_cb()</TT></A>:</p>
+
+<pre>
+ void message_cb(void *msg) {
+ ... do something with "msg" ...
+ }
+
+ int main() {
+ Fl::lock();
+ Fl::set_awake_cb(message_cb);
+ /* run thread */
+ return (Fl::run());
+ }
+</pre>
+
<P>FLTK supports multiple platforms, some of them which do not
allow any other but the main thread to handle system events and
open or close windows. The safe thing to do is to adhere to the
@@ -67,9 +86,9 @@ related methods that will handle system messages</li>
<P>See also:
<a href="Fl.html#Fl.awake">void awake(void *message)</A>,
<a href="Fl.html#Fl.lock">void lock()</A>,
-<a href="Fl.html#Fl.unlock">void unlock()</A>,
<a href="Fl.html#Fl.set_awake_cb">void set_awake_cb(void (*cb)(void *)</A>,
-<a href="Fl.html#Fl.thread_message">void *thread_message()</A>.
+<a href="Fl.html#Fl.thread_message">void *thread_message()</A>,
+<a href="Fl.html#Fl.unlock">void unlock()</A>.
</BODY>
</HTML>
diff --git a/test/threads.cxx b/test/threads.cxx
index 12ff5714f..fdd2f553c 100644
--- a/test/threads.cxx
+++ b/test/threads.cxx
@@ -62,22 +62,32 @@ void* prime_func(void* p)
// very simple prime number calculator !
for (;;) {
- int p;
+ int pp;
int hn = (int)sqrt((double)n);
- for (p=3; p<=hn; p+=2) if ( n%p == 0 ) break;
- if (p >= hn) {
+ 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();
- Fl::awake((void*) (browser == browser1? p:0)); // Cause the browser to redraw ...
+
+ // 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);
} else {
- // This should not be necessary since "n" and "step" a local variables,
+ // 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();
@@ -88,6 +98,12 @@ void* prime_func(void* p)
return 0;
}
+void message_cb(void *m) {
+ if (m == (void *)browser1) putchar('1');
+ else putchar('2');
+ fflush(stdout);
+}
+
int main(int argc, char **argv)
{
Fl_Window* w = new Fl_Window(200, 200, "Single Thread");
@@ -106,10 +122,22 @@ int main(int argc, char **argv)
browser1->add("Prime numbers:");
browser2->add("Prime numbers:");
- Fl::lock(); // you must do this before creating any threads!
+ // 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();
+
+ // Register a callback for Fl::awake() messages. This allows
+ // you to get all thread messages even if you are in another
+ // run loop (say, with a modal dialog...)
+ Fl::set_awake_cb(message_cb);
+
+ // 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);
@@ -118,12 +146,7 @@ int main(int argc, char **argv)
fl_create_thread(prime_thread, prime_func, browser2);
fl_create_thread(prime_thread, prime_func, browser2);
- // Fl::run();
- while (w->visible()) {
- Fl::wait();
-// void* m = Fl::thread_message();
-// printf("Received message: %p\n", m);
- }
+ Fl::run();
return 0;
}