0

I am making a command prompt that can create and remove (destroy) objects. You can interact with the objects via another commands and the values are sometimes exported (on request).

What if someone tries to delete object that is currently exporting or modifies any other value that's protected by a mutex? Then the mutexes are destroyed way before all operations/commands from the prompt.

How can I ensure that the object will be destroyed only after all commands that interact with it are finished? ( & when all mutexes are unlocked)

Is there any built-in functionality from std?

#include <iostream>
#include <thread>
#include <mutex>

class User
{
    private:
        int foo;
        int bar;
        
        std::mutex mu_foo;
        std::mutex mu_bar;
    public:
        User() {}
        ~User() {}
        void SetFoo(const int foo)
        {
            std::lock_guard<std::mutex> lock(mu_foo);
            this->foo = foo;
        }
        void SetBar(const int bar)
        {
            std::lock_guard<std::mutex> lock(mu_bar);
            this->bar = bar;
        }
        void Remove()
        {
            delete this;
        }
        void Export()
        {
            std::unique_lock<std::mutex> lock_foo(mu_foo);
            // export foo
            lock_foo.unlock();
            /*
                more exporting
            */
            std::unique_lock<std::mutex> lock_bar(mu_bar);
            // export foo
            lock_bar.unlock();
            /*
                more exporting
            */
        }
};

int main()
{
    User* user = new User();
    
    // simulate 2 commands from different clients
    //  if export was first - export and remove
    //  if remove was first - remove and dont allow to export
    
    std::thread t1([&user](){
        user->Export();
    });
    
    std::thread t2([&user](){
        user->Remove();
    });
    
    t1.join();
    t2.join();

    return 0;
}
nworder1
  • 1
  • 1
  • You may be able to use [`std::atomic> user;`](https://en.cppreference.com/w/cpp/memory/shared_ptr/atomic2) starting C++20... Each thread would retrieve the shared pointer via the `load` member function and check for null and instead of doing `user->Remove()` you'd simply use `store` to replace the the shared pointer with the empty one. – fabian Mar 24 '23 at 18:48
  • Don't use new/delete like this : This is useless use of pointers `User* user = new User();`. and `delete this;` really? .. where are you learning C++ from? [Avoid calling new/delete explicitly](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-newdelete) – Pepijn Kramer Mar 24 '23 at 18:48
  • 1
    Note that I'd consider the use of the raw pointer here the big issue: Any thread accessing it may retrieve that pointer value and be suspended before calling any member function that would do synchronization giving other threads time to call the `Remove` member function resulting in undefined behaviour once the suspended thread wakes up. Therefore you must manage the lifecycle via an external object. E.g. the atomic shared pointer mentioned in my previous comment. – fabian Mar 24 '23 at 18:53
  • @PepijnKramer :D Looks like you got triggered mate. Forgot to say that Remove does a lot more things than a normal destructor, that's why they are separated, there's actual functional difference between just deleting and cleaning up and some other work when REMOVING not JUST DELETING. Welp thanks anyway lol. – nworder1 Mar 26 '23 at 09:06

0 Answers0