Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing empty polymorphic Singleton type without magic statics

Suppose you had a polymorphic Singleton type (in our case a custom std::error_category type). The type is stateless, so no data members, but it does have a couple of virtual functions. The problem arises when instantiating this type in a multithreaded environment.

The easiest way to achieve this would be to use C++11's magic statics:

my_type const& instantiate() {
    static const my_type instance;
    return instance;
}

Unfortunately, one of our compilers (VC11) does not support this feature.

  • Should I expect that this will explode in a multithreaded environment? I'm quite certain that as far as the standard goes, all bets are off. But given that the type does not contain any data members and only virtual functions, what kind of errors should I expect from a mainstream implementation like VC11? For example, neither Boost.System nor VC seem to take any precautions against this in their implementation of error_category. Are they just being careless or is it unreasonably paranoid to worry about races here?
  • What would be the best way to get rid of the data race in a standard-compliant way? Since the type in this case is an error_category I want to avoid doing a heap allocation if possible. Keep in mind that the Singleton semantics are vital in this case, since equality of error categories is determined by pointer-comparison. This means that for example thread-local storage is not an option.
like image 802
ComicSansMS Avatar asked Apr 09 '26 19:04

ComicSansMS


1 Answers

Here is a possibly simpler version of Casey's answer, which uses an atomic spinlock to guard a normal static declaration.

my_type const& instantiate()
{
  static std::atomic_int flag;
  while (flag != 2)
  {
    int expected = 0;
    if (flag.compare_exchange_weak(expected, 1))
      break;
  }
  try
  {
    static my_type instance = whatever; // <--- normal static decl and init

    flag = 2;
    return instance;
  }
  catch (...)
  {
    flag = 0;
    throw;
  }
}

This code is also easier to turn into three macro's for reuse, which are easily #defined to nothing on platforms which support magic statics.

my_type const& instantiate()
{
  MY_MAGIC_STATIC_PRE;

  static my_type instance = whatever; // <--- normal static decl and init

  MY_MAGIC_STATIC_POST;

  return instance;

  MY_MAGIC_STATIC_SCOPE_END;
}
like image 200
Ian Avatar answered Apr 11 '26 22:04

Ian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!