C++ Logo

std-proposals

Advanced search

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

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Tue, 14 Feb 2023 10:52:13 +0000
On Tue, Feb 14, 2023 at 9:32 AM Frederick Virchanza Gotham wrote:
>
> Here's a sensible combination:
>
> void Func(void)
> noreentry_this_object(prevent_other_threads:skip)
> noreentry_all_objects(prevent_other_threads:wait)


I want to show just how much typing this would save. The following code snippet:

      struct Monkey {
         void Func(void) noreentry_this_object(prevent_other_threads:skip)

noreentry_all_objects(prevent_other_threads:wait)
          {
              // Main body of function goes here
          }
      };

is equivalent to the following:

#include <cassert> // assert
#include <atomic> // atomic_flag
#include <mutex> // defer_lock
#include <thread> // thread::id, this_thread::get_id

class atomic_flag_guard {
    std::atomic_flag &flag;
    std::atomic<std::thread::id> *p_id;
    bool previous;
public:
    atomic_flag_guard(std::atomic_flag &arg_flag,
std::atomic<std::thread::id> *arg_p_id, std::defer_lock_t) noexcept
    : flag(arg_flag), p_id(arg_p_id), previous(true) {}

    atomic_flag_guard(std::atomic_flag &arg_flag,
std::atomic<std::thread::id> *arg_p_id) noexcept
    : flag(arg_flag), p_id(arg_p_id), previous(flag.test_and_set()) {}

    bool try_lock(void) noexcept
    {
        assert( previous );

        previous = flag.test_and_set();

        if ( false == previous )
        {
            if ( nullptr != p_id )
            {
                assert( std::thread::id() == *p_id );
                *p_id = std::this_thread::get_id();
            }
        }

        return false == previous;
    }

    ~atomic_flag_guard(void) noexcept
    {
        if ( false == previous )
        {
            if ( nullptr != p_id )
            {
                assert( std::this_thread::get_id() == *p_id );
                *p_id = std::thread::id();
            }

            flag.clear();
            flag.notify_all();
        }
    }
};

struct Monkey {

    std::atomic_flag flag_for_this = ATOMIC_FLAG_INIT;

    void Func(void)
    {
        static std::atomic<std::thread::id> id_for_all{ std::thread::id() };
        static std::atomic_flag flag_for_all = ATOMIC_FLAG_INIT;

        atomic_flag_guard myguard_this(flag_for_this, nullptr ,
std::defer_lock);
        atomic_flag_guard myguard_all (flag_for_all , &id_for_all,
std::defer_lock);

        // The next line allows all kinds re-entry for the same thread
        if ( id_for_all != std::this_thread::get_id() )
        {
            if ( false == myguard_this.try_lock() )
            {
                // Here we skip
                return;
            }

            while ( false == myguard_all.try_lock() )
            {
                // Here we block
                flag_for_all.wait(true);
            }
        }

        // Main body of function goes here
    }
};

Received on 2023-02-14 10:52:26