Is a mutex defined statically in a function body able to lock properly?











up vote
7
down vote

favorite












Is a mutex defined statically in a function body able to lock properly? I am currently using this pattern in my logger system, but I have not tested it's thread safety yet.



void foo () {
static std::mutex mu;
std::lock_guard<std::mutex> guard(mu);
...
}









share|improve this question




























    up vote
    7
    down vote

    favorite












    Is a mutex defined statically in a function body able to lock properly? I am currently using this pattern in my logger system, but I have not tested it's thread safety yet.



    void foo () {
    static std::mutex mu;
    std::lock_guard<std::mutex> guard(mu);
    ...
    }









    share|improve this question


























      up vote
      7
      down vote

      favorite









      up vote
      7
      down vote

      favorite











      Is a mutex defined statically in a function body able to lock properly? I am currently using this pattern in my logger system, but I have not tested it's thread safety yet.



      void foo () {
      static std::mutex mu;
      std::lock_guard<std::mutex> guard(mu);
      ...
      }









      share|improve this question















      Is a mutex defined statically in a function body able to lock properly? I am currently using this pattern in my logger system, but I have not tested it's thread safety yet.



      void foo () {
      static std::mutex mu;
      std::lock_guard<std::mutex> guard(mu);
      ...
      }






      c++ multithreading thread-safety mutex static-variables






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 9 at 22:35









      NathanOliver

      83k15112173




      83k15112173










      asked Nov 9 at 22:13









      Soimn

      5315




      5315
























          2 Answers
          2






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          NathanOliver's answer is not accurate: mu is actually statically initialized – this means before any dynamic initialization, and therefore also before any user code could call mu.lock() (whether directly or by using std::lock_guard<std::mutex>).



          Nonetheless, your use case is safe – in fact, std::mutex initialization is even more safe than suggested by the previous answer.



          The reason for this is that any variable with static storage duration (✓ check) that is initialized with a constant expression (where a call to a constexpr constructor is explicitly considered as such – ✓ check), is constant initialized, which is a subset of static initialized. All static initialization happens strictly before all dynamic initialization, and hence before your function can be called the first time. (basic.start.static/2)



          This applies to std::mutex because std::mutex has only one viable constructor, the default constructor, and it is specified to be constexpr. (thread.mutex.class)



          Therefore, in addition to the usual atomicity guarantee that C++11 and higher makes for dynamic initialization of static variables at function scope, other std::mutex instances with static storage are also completely unaffected by initialization order issues, e.g.:



           #include <mutex>

          extern std::mutex mtx;
          unsigned counter = 0u;
          const auto count = { std::lock_guard<std::mutex> lock{mtx}; return ++counter; };
          const auto x = count(), y = count();
          std::mutex mtx;


          If mtx was dynamically initialized, this code would exhibit undefined behavior, because, then, mtx's initializer would run after that of the dynamically initialized x and y, and mtx would therefore be used before it is initialized.



          (In pthread, or common implementations of <thread> that use pthread, this effect is achieved by the use of the constant expression PTHREAD_MUTEX_INITIALIZER.)



          PS: This is also true for instances of std::atomic<T>, as long as the argument passed to the constructor is a constant expression. This means e.g. that you can easily make a spin lock based on std::atomic<IntT> that is immune to initialization order issues. std::once_flag has the same desirable property. A std::atomic_flag with static storage duration can also be statically initialized in either of two ways:




          • std::atomic_flag f;, is zero-initialized (because of static storage duration and because it has a trivial default c'tor). Note that the state of the flag is nonetheless unspecified, which makes this approach rather useless.


          • std::atomic_flag f = ATOMIC_FLAG_INIT; is constant initialized and unset. This is what you'd actually want to use.







          share|improve this answer






























            up vote
            10
            down vote













            Yes, this is fine. The first time the function is called mu will be initialized (and this is guaranteed to be thread safe and only happen once) and then guard will lock it. If another thread calls foo it will wait at



            std::lock_guard<std::mutex> guard(mu);


            until the first call to foo completes and guard is destroyed unlocking mu.






            share|improve this answer























              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














               

              draft saved


              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53233931%2fis-a-mutex-defined-statically-in-a-function-body-able-to-lock-properly%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              2
              down vote



              accepted










              NathanOliver's answer is not accurate: mu is actually statically initialized – this means before any dynamic initialization, and therefore also before any user code could call mu.lock() (whether directly or by using std::lock_guard<std::mutex>).



              Nonetheless, your use case is safe – in fact, std::mutex initialization is even more safe than suggested by the previous answer.



              The reason for this is that any variable with static storage duration (✓ check) that is initialized with a constant expression (where a call to a constexpr constructor is explicitly considered as such – ✓ check), is constant initialized, which is a subset of static initialized. All static initialization happens strictly before all dynamic initialization, and hence before your function can be called the first time. (basic.start.static/2)



              This applies to std::mutex because std::mutex has only one viable constructor, the default constructor, and it is specified to be constexpr. (thread.mutex.class)



              Therefore, in addition to the usual atomicity guarantee that C++11 and higher makes for dynamic initialization of static variables at function scope, other std::mutex instances with static storage are also completely unaffected by initialization order issues, e.g.:



               #include <mutex>

              extern std::mutex mtx;
              unsigned counter = 0u;
              const auto count = { std::lock_guard<std::mutex> lock{mtx}; return ++counter; };
              const auto x = count(), y = count();
              std::mutex mtx;


              If mtx was dynamically initialized, this code would exhibit undefined behavior, because, then, mtx's initializer would run after that of the dynamically initialized x and y, and mtx would therefore be used before it is initialized.



              (In pthread, or common implementations of <thread> that use pthread, this effect is achieved by the use of the constant expression PTHREAD_MUTEX_INITIALIZER.)



              PS: This is also true for instances of std::atomic<T>, as long as the argument passed to the constructor is a constant expression. This means e.g. that you can easily make a spin lock based on std::atomic<IntT> that is immune to initialization order issues. std::once_flag has the same desirable property. A std::atomic_flag with static storage duration can also be statically initialized in either of two ways:




              • std::atomic_flag f;, is zero-initialized (because of static storage duration and because it has a trivial default c'tor). Note that the state of the flag is nonetheless unspecified, which makes this approach rather useless.


              • std::atomic_flag f = ATOMIC_FLAG_INIT; is constant initialized and unset. This is what you'd actually want to use.







              share|improve this answer



























                up vote
                2
                down vote



                accepted










                NathanOliver's answer is not accurate: mu is actually statically initialized – this means before any dynamic initialization, and therefore also before any user code could call mu.lock() (whether directly or by using std::lock_guard<std::mutex>).



                Nonetheless, your use case is safe – in fact, std::mutex initialization is even more safe than suggested by the previous answer.



                The reason for this is that any variable with static storage duration (✓ check) that is initialized with a constant expression (where a call to a constexpr constructor is explicitly considered as such – ✓ check), is constant initialized, which is a subset of static initialized. All static initialization happens strictly before all dynamic initialization, and hence before your function can be called the first time. (basic.start.static/2)



                This applies to std::mutex because std::mutex has only one viable constructor, the default constructor, and it is specified to be constexpr. (thread.mutex.class)



                Therefore, in addition to the usual atomicity guarantee that C++11 and higher makes for dynamic initialization of static variables at function scope, other std::mutex instances with static storage are also completely unaffected by initialization order issues, e.g.:



                 #include <mutex>

                extern std::mutex mtx;
                unsigned counter = 0u;
                const auto count = { std::lock_guard<std::mutex> lock{mtx}; return ++counter; };
                const auto x = count(), y = count();
                std::mutex mtx;


                If mtx was dynamically initialized, this code would exhibit undefined behavior, because, then, mtx's initializer would run after that of the dynamically initialized x and y, and mtx would therefore be used before it is initialized.



                (In pthread, or common implementations of <thread> that use pthread, this effect is achieved by the use of the constant expression PTHREAD_MUTEX_INITIALIZER.)



                PS: This is also true for instances of std::atomic<T>, as long as the argument passed to the constructor is a constant expression. This means e.g. that you can easily make a spin lock based on std::atomic<IntT> that is immune to initialization order issues. std::once_flag has the same desirable property. A std::atomic_flag with static storage duration can also be statically initialized in either of two ways:




                • std::atomic_flag f;, is zero-initialized (because of static storage duration and because it has a trivial default c'tor). Note that the state of the flag is nonetheless unspecified, which makes this approach rather useless.


                • std::atomic_flag f = ATOMIC_FLAG_INIT; is constant initialized and unset. This is what you'd actually want to use.







                share|improve this answer

























                  up vote
                  2
                  down vote



                  accepted







                  up vote
                  2
                  down vote



                  accepted






                  NathanOliver's answer is not accurate: mu is actually statically initialized – this means before any dynamic initialization, and therefore also before any user code could call mu.lock() (whether directly or by using std::lock_guard<std::mutex>).



                  Nonetheless, your use case is safe – in fact, std::mutex initialization is even more safe than suggested by the previous answer.



                  The reason for this is that any variable with static storage duration (✓ check) that is initialized with a constant expression (where a call to a constexpr constructor is explicitly considered as such – ✓ check), is constant initialized, which is a subset of static initialized. All static initialization happens strictly before all dynamic initialization, and hence before your function can be called the first time. (basic.start.static/2)



                  This applies to std::mutex because std::mutex has only one viable constructor, the default constructor, and it is specified to be constexpr. (thread.mutex.class)



                  Therefore, in addition to the usual atomicity guarantee that C++11 and higher makes for dynamic initialization of static variables at function scope, other std::mutex instances with static storage are also completely unaffected by initialization order issues, e.g.:



                   #include <mutex>

                  extern std::mutex mtx;
                  unsigned counter = 0u;
                  const auto count = { std::lock_guard<std::mutex> lock{mtx}; return ++counter; };
                  const auto x = count(), y = count();
                  std::mutex mtx;


                  If mtx was dynamically initialized, this code would exhibit undefined behavior, because, then, mtx's initializer would run after that of the dynamically initialized x and y, and mtx would therefore be used before it is initialized.



                  (In pthread, or common implementations of <thread> that use pthread, this effect is achieved by the use of the constant expression PTHREAD_MUTEX_INITIALIZER.)



                  PS: This is also true for instances of std::atomic<T>, as long as the argument passed to the constructor is a constant expression. This means e.g. that you can easily make a spin lock based on std::atomic<IntT> that is immune to initialization order issues. std::once_flag has the same desirable property. A std::atomic_flag with static storage duration can also be statically initialized in either of two ways:




                  • std::atomic_flag f;, is zero-initialized (because of static storage duration and because it has a trivial default c'tor). Note that the state of the flag is nonetheless unspecified, which makes this approach rather useless.


                  • std::atomic_flag f = ATOMIC_FLAG_INIT; is constant initialized and unset. This is what you'd actually want to use.







                  share|improve this answer














                  NathanOliver's answer is not accurate: mu is actually statically initialized – this means before any dynamic initialization, and therefore also before any user code could call mu.lock() (whether directly or by using std::lock_guard<std::mutex>).



                  Nonetheless, your use case is safe – in fact, std::mutex initialization is even more safe than suggested by the previous answer.



                  The reason for this is that any variable with static storage duration (✓ check) that is initialized with a constant expression (where a call to a constexpr constructor is explicitly considered as such – ✓ check), is constant initialized, which is a subset of static initialized. All static initialization happens strictly before all dynamic initialization, and hence before your function can be called the first time. (basic.start.static/2)



                  This applies to std::mutex because std::mutex has only one viable constructor, the default constructor, and it is specified to be constexpr. (thread.mutex.class)



                  Therefore, in addition to the usual atomicity guarantee that C++11 and higher makes for dynamic initialization of static variables at function scope, other std::mutex instances with static storage are also completely unaffected by initialization order issues, e.g.:



                   #include <mutex>

                  extern std::mutex mtx;
                  unsigned counter = 0u;
                  const auto count = { std::lock_guard<std::mutex> lock{mtx}; return ++counter; };
                  const auto x = count(), y = count();
                  std::mutex mtx;


                  If mtx was dynamically initialized, this code would exhibit undefined behavior, because, then, mtx's initializer would run after that of the dynamically initialized x and y, and mtx would therefore be used before it is initialized.



                  (In pthread, or common implementations of <thread> that use pthread, this effect is achieved by the use of the constant expression PTHREAD_MUTEX_INITIALIZER.)



                  PS: This is also true for instances of std::atomic<T>, as long as the argument passed to the constructor is a constant expression. This means e.g. that you can easily make a spin lock based on std::atomic<IntT> that is immune to initialization order issues. std::once_flag has the same desirable property. A std::atomic_flag with static storage duration can also be statically initialized in either of two ways:




                  • std::atomic_flag f;, is zero-initialized (because of static storage duration and because it has a trivial default c'tor). Note that the state of the flag is nonetheless unspecified, which makes this approach rather useless.


                  • std::atomic_flag f = ATOMIC_FLAG_INIT; is constant initialized and unset. This is what you'd actually want to use.








                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 10 at 14:54

























                  answered Nov 10 at 14:34









                  Arne Vogel

                  3,74011125




                  3,74011125
























                      up vote
                      10
                      down vote













                      Yes, this is fine. The first time the function is called mu will be initialized (and this is guaranteed to be thread safe and only happen once) and then guard will lock it. If another thread calls foo it will wait at



                      std::lock_guard<std::mutex> guard(mu);


                      until the first call to foo completes and guard is destroyed unlocking mu.






                      share|improve this answer



























                        up vote
                        10
                        down vote













                        Yes, this is fine. The first time the function is called mu will be initialized (and this is guaranteed to be thread safe and only happen once) and then guard will lock it. If another thread calls foo it will wait at



                        std::lock_guard<std::mutex> guard(mu);


                        until the first call to foo completes and guard is destroyed unlocking mu.






                        share|improve this answer

























                          up vote
                          10
                          down vote










                          up vote
                          10
                          down vote









                          Yes, this is fine. The first time the function is called mu will be initialized (and this is guaranteed to be thread safe and only happen once) and then guard will lock it. If another thread calls foo it will wait at



                          std::lock_guard<std::mutex> guard(mu);


                          until the first call to foo completes and guard is destroyed unlocking mu.






                          share|improve this answer














                          Yes, this is fine. The first time the function is called mu will be initialized (and this is guaranteed to be thread safe and only happen once) and then guard will lock it. If another thread calls foo it will wait at



                          std::lock_guard<std::mutex> guard(mu);


                          until the first call to foo completes and guard is destroyed unlocking mu.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Nov 9 at 22:22

























                          answered Nov 9 at 22:16









                          NathanOliver

                          83k15112173




                          83k15112173






























                               

                              draft saved


                              draft discarded



















































                               


                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53233931%2fis-a-mutex-defined-statically-in-a-function-body-able-to-lock-properly%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              How to pass form data using jquery Ajax to insert data in database?

                              National Museum of Racing and Hall of Fame

                              Guess what letter conforming each word