C++ Logo

std-proposals

Advanced search

Re: [std-proposals] int Func(void) noreentry(-1)

From: Gergely Nagy <gergely.nagy.alt_at_[hidden]>
Date: Thu, 2 Feb 2023 13:16:59 +0100
This, especially noreentry_this_object is too convoluted to be a core
language feature.

Such a keyword would have to be generic, covering both single- and
multithreaded cases, and would require some state, that you can easily
implement yourself (just like you did, with the mutex).

void no_reentry_fn() {
    static std::mutex prevent;
    if (!prevent.try_lock()) return;
    std::scoped_lock prevent_l(prevent);
...
}

On Thu, Feb 2, 2023, 12:59 Frederick Virchanza Gotham via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> This week I had to fix a bug in a desktop GUI program. After doing
> some testing, I was leaning toward the possibility that one of the
> functions in the program was being re-entered (when it shouldn't be).
> For a quick solution to test my theory, I protected the function with
> a mutex as follows:
>
> int Func(void)
> {
> static mutex mtx;
> lock_guard<mutex> mylock;
>
> // The rest of the function goes here
> }
>
> After making this change, the program locked up completely. I was a
> little puzzled so I changed the 'mutex' to a 'recursive_mutex', and
> then it no longer locked up, but the original bug was still presenting
> itself.
>
> So I figured that this function is being re-entered by the same
> thread. This was because the function was an event handler for the
> GUI, and the GUI sometimes created nested event loops, which meant
> that an event handler could be re-entered by the same thread (for
> example if you displayed a modal dialog box inside a event handler).
>
> So I needed to protect this function from re-entry, not just by
> multiple threads but also by the same thread. It would be nice if
> there were a core-language feature for this, for example:
>
> int Func(void) noreentry(-1)
> {
> // The rest of the function goes here
> }
>
> The idea here is that the function would immediately return -1 if you
> tried to re-enter it. As 'Func' is a normal function (i.e. not a
> member function), the prevention of reentry would apply to the entire
> program.
>
> If it were a member function, for example:
>
> struct MyClass {
> int MemberFunc(void) noreentry_this_object(-1)
> {
> // The rest of the function goes here
> }
> };
>
> then the prevention of reentry only applies to the current object (not
> to all objects). Alternatively, if you want to ensure prevention of
> reentry of a member function for all objects, the syntax is:
>
> struct MyClass {
> int MemberFunc(void) noreentry_all_objects(-1)
> {
> // The rest of the function goes here
> }
> };
>
> So you can only apply "noreentry" to a normal function, and you can
> only apply "noreentry_this_object" and "noreentry_all_objects" to a
> member function. Note that you cannot apply 'noreentry' to a member
> function because I don't want the confusion.
>
> Behind the scenes, here is how each of them would work. Firstly I've
> made a 'lock_guard' class to be used with 'atomic_flag':
>
> #include <atomic>
>
> class atomic_flag_guard {
> std::atomic_flag &flag;
> bool const previous;
> public:
> atomic_flag_guard(std::atomic_flag &arg) noexcept
> : flag(arg), previous(flag.test_and_set()) {}
>
> ~atomic_flag_guard(void) noexcept
> {
> if ( false == previous ) flag.clear();
> }
>
> bool failed(void) const noexcept { return previous; }
> };
>
> Here's the implementation of the normal function:
>
> int Func(void)
> {
> static std::atomic_flag flag;
> atomic_flag_guard myguard(flag);
> if ( myguard.failed() ) return -1;
> // The rest of the function goes here
> }
>
> Here's the implementation of the member function:
>
> struct MyClass {
> std::atomic_flag flag;
> int MemberFunc(void)
> {
> atomic_flag_guard myguard(flag);
> if ( myguard.failed() ) return -1;
> // The rest of the function goes here
> }
> };
>
> And here's the implementation of the member function whereby reentry
> is prevented for all objects:
>
> struct MyClass {
> int MemberFunc(void)
> {
> static std::atomic_flag flag;
> atomic_flag_guard myguard(flag);
> if ( myguard.failed() ) return -1;
> // The rest of the function goes here
> }
> };
>
> I had considered a few other little things, for example let's say you
> want the function to throw an exception rather than return -1. The
> syntax would be something like:
>
> int Func(void) noreentry( throw runtime_error("cannot re-enter") )
> {
> // The rest of the function goes here
> }
>
> This new feature could be kept simple, or tt could made be very
> complex with extra parameters to do stuff like:
> * Prevent reentry by other threads but not by the same thread
> * Prevent reentry by the same thread but not by other threads
> * Prevent reentry by all threads except the one with the specified
> thread::id
>
> Mostly this feature would be used in desktop GUI programming, although
> someone might find another use for it. It would even be useful purely
> as a debugging tool.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2023-02-02 12:17:13