FLTK logo

Re: [fltk.coredev] RFC: Fl::enable_locks()

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.coredev  ]
 
Previous Message ]New Message | Reply ]Next Message ]

Re: RFC: Fl::enable_locks() Albrecht Schlosser Apr 19, 2021  
 
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 ]
 
     
Previous Message ]New Message | Reply ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.