1

I'm working with mutex and when building the code, its throwing an error: 'error: use of deleted function ‘std::mutex::mutex(const std::mutex&)'

I understand why I'm getting this error, referred to this answer: Attempting to reference a deleted function when using a mutex. Now, I don't know how can I actually acquire the mutex stored in the instance being copied. Any general example would help. Thanks!

EDIT

file.h

class A
{
    ...
    std::mutex taskMutex;
    bool isExecuting;
    ...
}

file.cpp

int function1
{
    std::unique_lock<std::mutex> lock(taskMutex);
    ...
    ( lambda func executing )
    isExecuting = true
    ...
    isExecuting = false
}

int function2
{
    while(isExecuting);
    std::unique_lock<std::mutex> lock(taskMutex);
}
Friday
  • 23
  • 1
  • 5
  • if the object has a `mutex` member in it to make its own member functions thread safe, then you don't need to copy it. Just let the member get default constructed so that each object has it's own mutex. – NathanOliver May 06 '22 at 12:05
  • Can you give more details about how you plan to use the mutex ? – limserhane May 06 '22 at 12:06
  • @limserhane I have two functions that are running on two different threads. I don't want these two functions to execute asynchronously. Hence, I'm using mutex to lock these two functions and then perform the execution. Also, don't know if this is relevant or not, one of these functions is lambda function. – Friday May 06 '22 at 12:13
  • Why is your mutex a class member ? Can you make it static ? – limserhane May 06 '22 at 12:14
  • You need to use the same mutex in both places. `std::shared_ptr` is the standard solution for shared object ownership. – molbdnilo May 06 '22 at 12:15
  • 1
    It would be a lot easier to help if you showed some relevant code. It almost sounds as if your class should itself be a model of 'lockable': i.e. provide it with `lock`, `unlock` etc. member functions. Just a guess though. – G.M. May 06 '22 at 12:17
  • 2
    Please show your class definition. If it's not obvious why it should be copyable, make it a [mre]. – Ted Lyngmo May 06 '22 at 12:25
  • You are copying an instance of a class with a mutex member. Should it be one mutex or two? Do you use the mutex for locking access to the class and/or something else? Are those two instances totally independent or do you need a common lock? Do you actually want to copy the class instance or is it just transferred through parameters and return types and copied on the way? – Sebastian May 06 '22 at 12:35
  • 2
    function2 is unsafe, do you know that? It can read isExecuting while it was written. – Swift - Friday Pie May 06 '22 at 12:42
  • @Sebastian I think one mutex would do. Need mutex for locking access. Need it for a common lock. – Friday May 06 '22 at 12:42
  • @Swift-FridayPie Thanks for pointing that out, I think using a conditional variable would do. Please let me know if that is the right approach. – Friday May 06 '22 at 12:43
  • One mutex is more strictly locked than two. In your example class A is not used. Are those member functions? Where is A copied? How do several instances of A come into play? Which data do function1 and function2 safeguard? The member variable isExecuting or also other data, which both would access? Are those functions called from different threads? From a callback or interrupt routine? – Sebastian May 06 '22 at 12:49

1 Answers1

0

Since each instance should be lockable, you need to lock the object while copying from it - which also may cause problems if it has non-default constructible member variables.

One idea could be to add a unique_lock member that can lock the object being copied or moved from while doing the copying/moving.

Here's an outline:

class Foo {
public:
    Foo() = default;

    Foo(const Foo& rhs) :  // copy constructor
        ul(rhs.mtx),       // lock the object being copied from
        member(rhs.member) // copy its members in the member initializer list
    {
        ul.unlock();       // unlock
    }

    Foo(Foo&& rhs) noexcept :         // move constructor
        ul(rhs.mtx),                  // lock the object being moved from
        member(std::move(rhs.member)) // move its members in the member init-list
    {
        ul.unlock();                  // unlock
    }

    Foo& operator=(const Foo& rhs) {         // copy assignment
        std::scoped_lock lock(mtx, rhs.mtx); // lock both objects involved
        member = rhs.member;                 // ... and copy
        return *this;
    }

    Foo& operator=(Foo&& rhs) noexcept {     // move assignment
        std::scoped_lock lock(mtx, rhs.mtx); // lock both objects involved
        member = std::move(rhs.member);      // ... and move
        return *this;
    }

private:
    std::unique_lock<std::mutex> ul; // used to lock rhs while copy/move constructing
    mutable std::mutex mtx;
    std::string member;
};

Note that the mutex and unique_lock member variables are not copied or moved at any time.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108