Date: Wed, 28 Jun 2023 11:30:05 +0100
On Wed, Jun 28, 2023 at 10:53 AM Breno GuimarĂ£es via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
>
> Then all access to the variable just need to check a boolean (in the hot path) instead of calling an opaque function.
>
> I also don't see the need for a mutex on the initialization. The global call_once flag should be enough. The thread local variable shouldn't need to be atomic either.
Here's what I've got now using a thread_local boolean, and relying on
the once_flag to do all the required synchronisation:
https://godbolt.org/z/Gavo7vf9G
And here it is copy-pasted:
#include <optional> // optional
#include <mutex> // once_flag, call_once
#include <iostream> // Just for testing: cout, endl
#include <thread> // Just for testing: jthread,
get_id, sleep_for
#include <chrono> // Just for testing: milliseconds
struct T {
T(void) { std::cout << "Constructing. . .\n"; }
~T(void) { std::cout << "Destroying. . .\n" ; }
void Speak(void) { std::cout << "Hi!\n"; }
};
std::optional<T> g_optional;
/* Note that the following variable is thread_local */
thread_local bool g_is_initialised = false;
std::once_flag g_flag_for_optional{};
T &Func(void)
{
std::cout << "- - - Func " << std::this_thread::get_id() << " --- ";
if ( g_is_initialised )
{
std::cout << "true\n";
return *g_optional.operator->(); // crashes instead of throwing
}
std::cout << "false\n";
std::call_once(g_flag_for_optional, []() { g_optional.emplace(); });
g_is_initialised = true; // This variable is thread_local
return *g_optional.operator->(); // crashes instead of throwing
}
#define g_obj (Func())
int main(void)
{
g_obj.Speak();
std::jthread mythread( []()
{
std::this_thread::sleep_for( std::chrono::milliseconds(20u) );
g_obj.Speak();
std::this_thread::sleep_for( std::chrono::milliseconds(105u) );
g_obj.Speak();
} );
std::this_thread::sleep_for( std::chrono::milliseconds(120u) );
g_obj.Speak();
g_obj.Speak();
g_obj.Speak();
}
<std-proposals_at_[hidden]> wrote:
>
>
> Then all access to the variable just need to check a boolean (in the hot path) instead of calling an opaque function.
>
> I also don't see the need for a mutex on the initialization. The global call_once flag should be enough. The thread local variable shouldn't need to be atomic either.
Here's what I've got now using a thread_local boolean, and relying on
the once_flag to do all the required synchronisation:
https://godbolt.org/z/Gavo7vf9G
And here it is copy-pasted:
#include <optional> // optional
#include <mutex> // once_flag, call_once
#include <iostream> // Just for testing: cout, endl
#include <thread> // Just for testing: jthread,
get_id, sleep_for
#include <chrono> // Just for testing: milliseconds
struct T {
T(void) { std::cout << "Constructing. . .\n"; }
~T(void) { std::cout << "Destroying. . .\n" ; }
void Speak(void) { std::cout << "Hi!\n"; }
};
std::optional<T> g_optional;
/* Note that the following variable is thread_local */
thread_local bool g_is_initialised = false;
std::once_flag g_flag_for_optional{};
T &Func(void)
{
std::cout << "- - - Func " << std::this_thread::get_id() << " --- ";
if ( g_is_initialised )
{
std::cout << "true\n";
return *g_optional.operator->(); // crashes instead of throwing
}
std::cout << "false\n";
std::call_once(g_flag_for_optional, []() { g_optional.emplace(); });
g_is_initialised = true; // This variable is thread_local
return *g_optional.operator->(); // crashes instead of throwing
}
#define g_obj (Func())
int main(void)
{
g_obj.Speak();
std::jthread mythread( []()
{
std::this_thread::sleep_for( std::chrono::milliseconds(20u) );
g_obj.Speak();
std::this_thread::sleep_for( std::chrono::milliseconds(105u) );
g_obj.Speak();
} );
std::this_thread::sleep_for( std::chrono::milliseconds(120u) );
g_obj.Speak();
g_obj.Speak();
g_obj.Speak();
}
Received on 2023-06-28 10:30:17