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
}
};
>
> 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