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
This commit is contained in:
Michael R Sweet
2007-02-12 16:00:28 +00:00
parent ded0bf0432
commit b5d637a4cd
2 changed files with 71 additions and 29 deletions
+35 -16
View File
@@ -15,31 +15,50 @@ 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
@@ -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>
+35 -12
View File
@@ -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;
}