How to perform double buffering with atomic pointers?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite
1












Atomic newbie here. My code currently looks like this (simplified):



std::atomic<Object*> object;

void thread_a()

object.load()->doSomething(); // (1)


void thread_b()

Object* oldObject = object.load();
Object* newObject = new Object();
// Update new object accordingly...

while (!object.compare_exchange_weak(oldObject, newObject));

delete oldObject;



In words, my idea is to let thread_b atomically swap the shared object (double-buffering), while thread_a performs some work on it. My question: can I safely assume that the shared object will be "protected" against data races while thread_a calls doSomething() on it, as done in (1)?










share|improve this question

























    up vote
    6
    down vote

    favorite
    1












    Atomic newbie here. My code currently looks like this (simplified):



    std::atomic<Object*> object;

    void thread_a()

    object.load()->doSomething(); // (1)


    void thread_b()

    Object* oldObject = object.load();
    Object* newObject = new Object();
    // Update new object accordingly...

    while (!object.compare_exchange_weak(oldObject, newObject));

    delete oldObject;



    In words, my idea is to let thread_b atomically swap the shared object (double-buffering), while thread_a performs some work on it. My question: can I safely assume that the shared object will be "protected" against data races while thread_a calls doSomething() on it, as done in (1)?










    share|improve this question























      up vote
      6
      down vote

      favorite
      1









      up vote
      6
      down vote

      favorite
      1






      1





      Atomic newbie here. My code currently looks like this (simplified):



      std::atomic<Object*> object;

      void thread_a()

      object.load()->doSomething(); // (1)


      void thread_b()

      Object* oldObject = object.load();
      Object* newObject = new Object();
      // Update new object accordingly...

      while (!object.compare_exchange_weak(oldObject, newObject));

      delete oldObject;



      In words, my idea is to let thread_b atomically swap the shared object (double-buffering), while thread_a performs some work on it. My question: can I safely assume that the shared object will be "protected" against data races while thread_a calls doSomething() on it, as done in (1)?










      share|improve this question













      Atomic newbie here. My code currently looks like this (simplified):



      std::atomic<Object*> object;

      void thread_a()

      object.load()->doSomething(); // (1)


      void thread_b()

      Object* oldObject = object.load();
      Object* newObject = new Object();
      // Update new object accordingly...

      while (!object.compare_exchange_weak(oldObject, newObject));

      delete oldObject;



      In words, my idea is to let thread_b atomically swap the shared object (double-buffering), while thread_a performs some work on it. My question: can I safely assume that the shared object will be "protected" against data races while thread_a calls doSomething() on it, as done in (1)?







      c++ multithreading atomic






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked 2 hours ago









      Ignorant

      345620




      345620






















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          7
          down vote













          The fetching of the pointer with load() will be atomic, but the call to doSomething() itself will not be atomic.



          That means the pointers could be swapped after load() is called but before doSomething() is called (which means doSomething() is called on the wrong and now deleted object).



          Perhaps a mutex could be a better choice here?






          share|improve this answer






















          • Yes, a mutex would definitely be a better/easier choice :) However I'm trying to investigate the lock-free way of doing this kind of things. Is the atomic double-buffering not doable in your opinion?
            – Ignorant
            2 hours ago











          • @Ignorant IMO not the way you have implemented it anyway. Perhaps if you used smart pointers (e.g. std::unique_ptr<Object>) instead. Then the worst that could happen is that you call doSomething() on an object that isn't "active" but at least it will still exist.
            – Some programmer dude
            2 mins ago

















          up vote
          2
          down vote













          I do this quite often, but... with shared pointers, and it's lock-free!



          There's a problem with your design, as Some Programmer Dude suggested in his answer. But if you do this with shared_ptr, and your program logic allows it, you'll be fine.



          The reason why this works with shared_ptr is that your object will not be deleted by force, as long as it lives somewhere else. So, this is how you do it:



          std::shared_ptr<Object> object;

          void thread_a()

          std::atomic_load(&object)->doSomething(); // (1)


          void thread_b()

          std::shared_ptr<Object> oldObject = std::atomic_load(&object);
          std::shared_ptr<Object> newObject = std::make_shared<Object>();
          // Update new object accordingly...

          while (!std::atomic_compare_exchange_weak(object, oldObject, newObject));






          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: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            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%2f53061020%2fhow-to-perform-double-buffering-with-atomic-pointers%23new-answer', 'question_page');

            );

            Post as a guest






























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            7
            down vote













            The fetching of the pointer with load() will be atomic, but the call to doSomething() itself will not be atomic.



            That means the pointers could be swapped after load() is called but before doSomething() is called (which means doSomething() is called on the wrong and now deleted object).



            Perhaps a mutex could be a better choice here?






            share|improve this answer






















            • Yes, a mutex would definitely be a better/easier choice :) However I'm trying to investigate the lock-free way of doing this kind of things. Is the atomic double-buffering not doable in your opinion?
              – Ignorant
              2 hours ago











            • @Ignorant IMO not the way you have implemented it anyway. Perhaps if you used smart pointers (e.g. std::unique_ptr<Object>) instead. Then the worst that could happen is that you call doSomething() on an object that isn't "active" but at least it will still exist.
              – Some programmer dude
              2 mins ago














            up vote
            7
            down vote













            The fetching of the pointer with load() will be atomic, but the call to doSomething() itself will not be atomic.



            That means the pointers could be swapped after load() is called but before doSomething() is called (which means doSomething() is called on the wrong and now deleted object).



            Perhaps a mutex could be a better choice here?






            share|improve this answer






















            • Yes, a mutex would definitely be a better/easier choice :) However I'm trying to investigate the lock-free way of doing this kind of things. Is the atomic double-buffering not doable in your opinion?
              – Ignorant
              2 hours ago











            • @Ignorant IMO not the way you have implemented it anyway. Perhaps if you used smart pointers (e.g. std::unique_ptr<Object>) instead. Then the worst that could happen is that you call doSomething() on an object that isn't "active" but at least it will still exist.
              – Some programmer dude
              2 mins ago












            up vote
            7
            down vote










            up vote
            7
            down vote









            The fetching of the pointer with load() will be atomic, but the call to doSomething() itself will not be atomic.



            That means the pointers could be swapped after load() is called but before doSomething() is called (which means doSomething() is called on the wrong and now deleted object).



            Perhaps a mutex could be a better choice here?






            share|improve this answer














            The fetching of the pointer with load() will be atomic, but the call to doSomething() itself will not be atomic.



            That means the pointers could be swapped after load() is called but before doSomething() is called (which means doSomething() is called on the wrong and now deleted object).



            Perhaps a mutex could be a better choice here?







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 2 hours ago

























            answered 2 hours ago









            Some programmer dude

            287k24235396




            287k24235396











            • Yes, a mutex would definitely be a better/easier choice :) However I'm trying to investigate the lock-free way of doing this kind of things. Is the atomic double-buffering not doable in your opinion?
              – Ignorant
              2 hours ago











            • @Ignorant IMO not the way you have implemented it anyway. Perhaps if you used smart pointers (e.g. std::unique_ptr<Object>) instead. Then the worst that could happen is that you call doSomething() on an object that isn't "active" but at least it will still exist.
              – Some programmer dude
              2 mins ago
















            • Yes, a mutex would definitely be a better/easier choice :) However I'm trying to investigate the lock-free way of doing this kind of things. Is the atomic double-buffering not doable in your opinion?
              – Ignorant
              2 hours ago











            • @Ignorant IMO not the way you have implemented it anyway. Perhaps if you used smart pointers (e.g. std::unique_ptr<Object>) instead. Then the worst that could happen is that you call doSomething() on an object that isn't "active" but at least it will still exist.
              – Some programmer dude
              2 mins ago















            Yes, a mutex would definitely be a better/easier choice :) However I'm trying to investigate the lock-free way of doing this kind of things. Is the atomic double-buffering not doable in your opinion?
            – Ignorant
            2 hours ago





            Yes, a mutex would definitely be a better/easier choice :) However I'm trying to investigate the lock-free way of doing this kind of things. Is the atomic double-buffering not doable in your opinion?
            – Ignorant
            2 hours ago













            @Ignorant IMO not the way you have implemented it anyway. Perhaps if you used smart pointers (e.g. std::unique_ptr<Object>) instead. Then the worst that could happen is that you call doSomething() on an object that isn't "active" but at least it will still exist.
            – Some programmer dude
            2 mins ago




            @Ignorant IMO not the way you have implemented it anyway. Perhaps if you used smart pointers (e.g. std::unique_ptr<Object>) instead. Then the worst that could happen is that you call doSomething() on an object that isn't "active" but at least it will still exist.
            – Some programmer dude
            2 mins ago












            up vote
            2
            down vote













            I do this quite often, but... with shared pointers, and it's lock-free!



            There's a problem with your design, as Some Programmer Dude suggested in his answer. But if you do this with shared_ptr, and your program logic allows it, you'll be fine.



            The reason why this works with shared_ptr is that your object will not be deleted by force, as long as it lives somewhere else. So, this is how you do it:



            std::shared_ptr<Object> object;

            void thread_a()

            std::atomic_load(&object)->doSomething(); // (1)


            void thread_b()

            std::shared_ptr<Object> oldObject = std::atomic_load(&object);
            std::shared_ptr<Object> newObject = std::make_shared<Object>();
            // Update new object accordingly...

            while (!std::atomic_compare_exchange_weak(object, oldObject, newObject));






            share|improve this answer


























              up vote
              2
              down vote













              I do this quite often, but... with shared pointers, and it's lock-free!



              There's a problem with your design, as Some Programmer Dude suggested in his answer. But if you do this with shared_ptr, and your program logic allows it, you'll be fine.



              The reason why this works with shared_ptr is that your object will not be deleted by force, as long as it lives somewhere else. So, this is how you do it:



              std::shared_ptr<Object> object;

              void thread_a()

              std::atomic_load(&object)->doSomething(); // (1)


              void thread_b()

              std::shared_ptr<Object> oldObject = std::atomic_load(&object);
              std::shared_ptr<Object> newObject = std::make_shared<Object>();
              // Update new object accordingly...

              while (!std::atomic_compare_exchange_weak(object, oldObject, newObject));






              share|improve this answer
























                up vote
                2
                down vote










                up vote
                2
                down vote









                I do this quite often, but... with shared pointers, and it's lock-free!



                There's a problem with your design, as Some Programmer Dude suggested in his answer. But if you do this with shared_ptr, and your program logic allows it, you'll be fine.



                The reason why this works with shared_ptr is that your object will not be deleted by force, as long as it lives somewhere else. So, this is how you do it:



                std::shared_ptr<Object> object;

                void thread_a()

                std::atomic_load(&object)->doSomething(); // (1)


                void thread_b()

                std::shared_ptr<Object> oldObject = std::atomic_load(&object);
                std::shared_ptr<Object> newObject = std::make_shared<Object>();
                // Update new object accordingly...

                while (!std::atomic_compare_exchange_weak(object, oldObject, newObject));






                share|improve this answer














                I do this quite often, but... with shared pointers, and it's lock-free!



                There's a problem with your design, as Some Programmer Dude suggested in his answer. But if you do this with shared_ptr, and your program logic allows it, you'll be fine.



                The reason why this works with shared_ptr is that your object will not be deleted by force, as long as it lives somewhere else. So, this is how you do it:



                std::shared_ptr<Object> object;

                void thread_a()

                std::atomic_load(&object)->doSomething(); // (1)


                void thread_b()

                std::shared_ptr<Object> oldObject = std::atomic_load(&object);
                std::shared_ptr<Object> newObject = std::make_shared<Object>();
                // Update new object accordingly...

                while (!std::atomic_compare_exchange_weak(object, oldObject, newObject));







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 1 hour ago

























                answered 1 hour ago









                The Quantum Physicist

                10.4k64392




                10.4k64392



























                     

                    draft saved


                    draft discarded















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53061020%2fhow-to-perform-double-buffering-with-atomic-pointers%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Comments

                    Popular posts from this blog

                    What does second last employer means? [closed]

                    List of Gilmore Girls characters

                    Confectionery