|
|
On 4/18/21 9:08 PM Greg Ercolano wrote:
On 4/18/21 11:10 AM, Michael Sweet wrote:
On Apr 18, 2021, at 1:33 PM, Greg Ercolano<erco@seriss.com> wrote:
Right, that'd be great if possible.
We just have to make sure that if FLTK starts with locks enabled, old apps calling Fl::lock()
before run() won't hang on the lock call.
My thought was that Fl::lock() and Fl::unlock() could be no-ops until Fl::run() is called.
Sounds worth trying.
I don't think that this would be a good idea. See notes below.
Perhaps we can test this by sticking this into 1.4.x and see if
anything shakes out from dev testing.
The safe thing to do would be to make a new configure/cmake flag
for it (default on)
that can be turned off to disable the new behavior if it causes
trouble.
Whatever we do, using configure or CMake flags should IMHO not change
such basic behavior. Think of Linux and other distros providing FLTK.
What should they do, which options should they choose? If there are too
many options this would likely force more and more users to build their
own versions of FLTK.
Going back to the original problem: after thinking about it (and looking
at the code/comments) it became clear to me that the user must be able
to call Fl::lock() before calling Fl::run() and that the call before
Fl::run() must not be a no-op.
Reasoning:
(1) First a code comment, likely from Bill, in src/Fl_lock.cxx:
```
The API:
Fl::lock() - recursive lock. You must call this before the
first call to Fl::wait()/run() to initialize the thread
system. The lock is locked all the time except when
Fl::wait() is waiting for events.
```
So, what does this say? First of all, Fl::lock() is a recursive lock.
You must call it /exactly/ once /before/ Fl::run() is called. Let aside
the phrase "to initialize the thread system". This is only relevant to
distinguish multithreaded and singlethreaded FLTK applications.
We should update the documentation accordingly and clarify this fact.
(2) Why do we need to use an operational (not a no-op) call of
Fl::lock() /before/ calling Fl::run()?
It's about initialization of threads that need access to FLTK data and
call Fl::lock() / Fl::unlock() later. The attached file
fltk_test_threads_cxx.txt is an excerpt from our test/threads.cxx:
shortened but with additional comments marked "// # ".
Please read the comments carefully.
Although there might be other solutions (see FLTK docs about "lockless
operation" in the "Advanced FLTK" chapter) this is a valid FLTK program
that should make clear (in general) why the Fl::lock() call before
Fl::run() must not be a no-op.
Please don't say "it doesn't matter if the child threads are locked or
not". There may be cases in user programs where it DOES matter.
(3) I withdraw my proposal to add a parameter to Fl::run() to start
locking with an initial Fl::lock() inside Fl::run() because there are
valid scenarios (see 2 above) that need to call Fl::lock() before
calling Fl::run(). This would only make it more complicated than necessary.
Note that Fl::lock() must not (accidentally) be called twice because it
is a recursive lock.
After all I believe the current behavior
(a) is correct and
(b) can't be improved much.
If we want to support single-threaded programs w/o the requirement to
call Fl::lock() [and I think we do, see test/hello.cxx] we should not
enforce calling Fl::lock() in any way.
I propose however to clarify the docs and particularly mention the
difference of running FLTK single-threaded (w/o Fl::lock()) vs
multi-threaded (with Fl::lock()).
That said, I also believe that adding another method like
Fl::enable_locks() is not helpful and would make the entire stuff even
more confusing.
Ian provided some interesting aspects why we may still want to keep the
ability to run FLTK in single-threaded mode. Thanks.
--
You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fltkcoredev/bb6eba0e-8f7e-758c-019d-3076ed9f1d8e%40online.de.
int main(int argc, char **argv) {
// # general FLTK initialization w/o Fl::lock()
Fl_Double_Window* w = new Fl_Double_Window(200, 200, "Single Thread");
// # window initialization goes here
w->end();
w->show();
browser1->add("Prime numbers:");
browser2->add("Prime numbers:");
// Enable multi-thread support by locking from the main thread.
Fl::lock();
// # Start (child) threads AFTER Fl::lock() ...
// 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);
// # start more threads.
// # You could do even more FLTK initializations here
// # w/o interfering with the child threads because
// # the FLTK lock is held...
// # WE MUST NOT release the lock because otherwise
// # the child threads could acquire the lock before
// # the FLTK event loop gets started (race condition).
Fl::run();
return 0;
}
[ Direct Link to Message ] | |
|
| |