C++在构造函数中将互斥锁传递给成员变量

4

我有一个问题,关于如何将互斥锁传递给我的类。我的类名为Test,其中有一个成员变量叫做m_Mutex。在构造函数中,我想将参数互斥锁传递给m_Mutex

我的类:

#include <mutex>

class Test
{
public:
    Test(mutex &mtx) :
        m_Mutex(mtx)
    {
    }

private:
    mutex m_Mutex;
};

我的主程序:

int main()
{
   mutex mutex1;
   Test t(mutex1);
   return 0;
} 

错误:

"std::mutex::mutex(const std::mutex &)"函数(在"c:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include\mutex"的第88行声明)无法引用——它是一个已删除的函数

我为什么会得到这个错误,如何修复它以便我能够传递互斥量?


听起来像是 XY 问题,你为什么需要在第一时间传递互斥锁呢? - Slava
5个回答

7
简而言之:你不能。互斥锁既不能复制也不能移动。这并非没有原因。但是如果你仍想实现这一点,可以使用unique_ptr传递它:
class A {
   unique_ptr<mutex> mutexPtr;

   A(unique_ptr<mutex> ptr) : mutexPtr(std::move(ptr)) { }
};

A a{std::make_unique<mutex>()};

请注意,如果您想在不同对象之间共享互斥锁,应该使用 shared_ptr 或 weak_ptr。

不知道 OP 为什么需要传递它,这个答案可能不适用。 - Slava
总的来说,拥有可移动/可复制的互斥锁并不是一个好主意。我想OP有一个很好的理由,并且知道自己在做什么。这就是为什么我写的互斥锁被构建成这样的原因。 - Jodocus
1
但你的答案应该使用shared_ptr,因为我在这里看不到使用unique_ptr的理由。 - Slava
@ UKMonkey:为了确保它保持活动状态。当传递一个普通引用时,整个对象在互斥体过期时变得无效,而且没有办法找出原因。当然,您也可以使用weak_ptr,这样您就不必传递所有权,但仍然可以检查引用是否仍然有效。 - Jodocus
@ Pierrot:我假设该对象将以多线程方式使用。如果使用了在不同线程创建的互斥量的引用,那么一个线程可能会使另一个线程的对象无效。这是非常不可取的行为!如果您看到更简单(但安全!)的解决方案,请随时发布它。 - Jodocus
显示剩余6条评论

3
在构造函数中,我想将参数mutex转移到`m_Mutex`中。
抱歉,这是不可能的。`std::mutex`既不可复制也不可移动。如果你想在其他地方声明mutex,则可以像下面这样存储mutex的引用:
class Test
{
public:
    Test(mutex &mtx) :
        m_Mutex(mtx)
    {
    }

private:
    mutex& m_Mutex;
};

2
这是潜在的危险,因为在Test内部没有办法找出互斥锁引用是否仍然有效。如果您想共享所有权,则应改用shared_ptr(或weak_ptr)。 - Jodocus
我可以在Test类的其他函数中使用m_Mutex.lock()m_Mutex.unlock()来锁定和解锁互斥量吗? - User987123
@User987123 是的,但类本身变得不可复制和不可移动。Jodocus的解决方案使用智能指针将允许您移动/可能复制它。 - NathanOliver

2
#include <mutex>

class Test
{
public:
Test(std::mutex &mtx) :         
    m_Mutex(mtx)
{
}

private:
std::mutex &m_Mutex;           // note the "&"
};


int main()
{
 std::mutex mutex1;
 Test t(mutex1);
 return 0;
}

1
这应该真正解释了为什么成员变量需要是引用才能成为一个好的答案(以NathanOlivers的回答为例)。 - UKMonkey

2

只需将互斥锁放在您的类内部(可能作为静态成员),如果您需要允许其他类使用它,请提供访问权限:

class Test 
{
public:
    Test() {}
    std::mutex &mux() { return m_Mutex; }
private:
    mutex m_Mutex;
};

甚至是这个:
class Test {
public:
    using lock_t = std::scoped_lock<std::mutex>;
    Test() {}

    lock_t lock() { return lock_t( m_Mutex ); }
private:
    mutex m_Mutex;
};

用法:

Test t;
{
    auto lock = t.lock();
    // object t is locked till end of the block
}

0

只需将其作为参考

您的互斥锁必须对类的所有实例相同,如果不是这种情况,则在类的一个实例中执行的锁定对于另一个实例不起作用。

#include <mutex>
#include <iostream>

using namespace std;

class Test
{
public:
    Test(mutex &mtx) :
        m_Mutex(mtx)
    {
            m_Mutex.lock();
            i++;
            cout << "Test " <<i<<endl;
            m_Mutex.unlock();
    }

private:
    mutex& m_Mutex;
    static int i;
};

int Test::i =0;

int main()
{
   mutex mutex1;
   Test t1(mutex1);
   Test t2(mutex1);
   return 0;
} 

点此查看实时效果:https://wandbox.org/permlink/6YJFG3MI7m7RbfoL


为什么你想要一个const互斥锁?你打算如何加锁? - UKMonkey
std::mutex::lock() 不是一个 const 方法。 - Slava
抱歉,我想指出这个问题应该使用const关键字才符合逻辑,但它不起作用。但我发现这将会导致错误的代码推广,这是不好的。 - Pierrot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接