在不复制此变量或互斥变量的情况下访问类成员

Posted

技术标签:

【中文标题】在不复制此变量或互斥变量的情况下访问类成员【英文标题】:Access class members without copying this or mutex variable 【发布时间】:2020-02-17 12:15:40 【问题描述】:

我正在尝试创建一个简单的 Worker 类,它将创建多个线程和一组任务以供线程运行。这是有教育意义的,但我已经尝试过询问同学并寻找不同的答案,我认为这里缺少一些“简单”/基本的东西。

我遇到了一些关于应该在哪里设置互斥变量的问题。我相信我的每个 Worker 对象都需要一个,因为每个对象创建的线程完全不相关。现在,我正在尝试将 this 传递给添加到线程集的 lambda 方法,但这会复制互斥体,从而将其删除。有没有办法独立复制我需要的每个类成员,或者我应该创建一个复制构造函数?我只是想将我需要的类变量传递给 lambda。这是我的代码:

// TDAT2004Task2.cpp : Defines the entry point for the application.
//

#include <functional>
#include <iostream>
#include <list>
#include <vector>
#include <mutex>
#include <thread>

using namespace std;

class Worker 
    int threads;

    mutable mutex tasks_mutex;

    vector<thread> worker_threads;
    list<function<void()>> tasks;

public:

    Worker(int threadAmount) 
        threads = threadAmount;
    


    void start() 
        for (int i = 0; i < threads; i++) 
            //This is the place errors occur. I'm copying the this element, and thus deleting my 
            //mutex variable.
            worker_threads.emplace_back([this] 
                while (true) 
                    function<void()> task;
                    
                        lock_guard<mutex> lock(tasks_mutex);
                        if (!tasks.empty()) 
                            task = *tasks.begin();
                            tasks.pop_front();
                        
                    
                    if (task) 
                        task();
                    
                
                );
        
        for (auto& thread : worker_threads) 
            thread.join();
        
    

    void post(function<void()> function) 
        lock_guard<mutex> lock(tasks_mutex);
        tasks.emplace_back(function);
    
;


int main()

    //This does not compile. 
    Worker worker_threads = Worker(4);

我在 VS 中的错误信息:

>------ Build All started: Project: TDAT2004Task2, Configuration: x64-Debug ------
  [1/2] C:\PROGRA~2\MICROS~2\2019\COMMUN~1\VC\Tools\MSVC\1424~1.283\bin\HostX64\x64\cl.exe  /nologo /TP   /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1 /showIncludes /FoTDAT2004Task2\CMakeFiles\TDAT2004Task2.dir\TDAT2004Task2.cpp.obj /FdTDAT2004Task2\CMakeFiles\TDAT2004Task2.dir\ /FS -c ..\..\..\TDAT2004Task2\TDAT2004Task2.cpp
  FAILED: TDAT2004Task2/CMakeFiles/TDAT2004Task2.dir/TDAT2004Task2.cpp.obj 
  C:\PROGRA~2\MICROS~2\2019\COMMUN~1\VC\Tools\MSVC\1424~1.283\bin\HostX64\x64\cl.exe  /nologo /TP   /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1 /showIncludes /FoTDAT2004Task2\CMakeFiles\TDAT2004Task2.dir\TDAT2004Task2.cpp.obj /FdTDAT2004Task2\CMakeFiles\TDAT2004Task2.dir\ /FS -c ..\..\..\TDAT2004Task2\TDAT2004Task2.cpp
C:\Users\Even\source\repos\TDAT2004Task2\TDAT2004Task2\TDAT2004Task2.cpp(74): error C2280: 'Worker::Worker(const Worker &)': attempting to reference a deleted function
  ..\..\..\TDAT2004Task2\TDAT2004Task2.cpp(69): note: compiler has generated 'Worker::Worker' here
  ..\..\..\TDAT2004Task2\TDAT2004Task2.cpp(69): note: 'Worker::Worker(const Worker &)': function was implicitly deleted because a data member invokes a deleted or inaccessible function 'std::mutex::mutex(const std::mutex &)'
  C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\include\mutex(92): note: 'std::mutex::mutex(const std::mutex &)': function was explicitly deleted
  ninja: build stopped: subcommand failed.

控制台中来自 cpp 的错误消息:

C:\Users\Even\source\repos\TDAT2004Task2\TDAT2004Task2>gcc TDAT2004Task2.cpp
TDAT2004Task2.cpp: In function 'int main()':
TDAT2004Task2.cpp:74:34: error: use of deleted function 'Worker::Worker(Worker&&)'
  Worker worker_threads = Worker(4);
                                  ^
TDAT2004Task2.cpp:18:7: note: 'Worker::Worker(Worker&&)' is implicitly deleted because the default definition would be ill-formed:
 class Worker 
       ^~~~~~
TDAT2004Task2.cpp:18:7: error: use of deleted function 'std::mutex::mutex(const std::mutex&)'
In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/mutex:43:0,
                 from TDAT2004Task2.cpp:13:
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/include/c++/bits/std_mutex.h:97:5: note: declared here
     mutex(const mutex&) = delete;
     ^~~~~

感谢您的任何回复!请指出我犯过的任何愚蠢的错误,我只是想学习最佳实践。

【问题讨论】:

传递this 不会复制对象。 this 是一个指针。 "错误 C2280: 'Worker::Worker(const Worker &)': 试图引用已删除的函数""错误:使用已删除的函数' Worker::Worker(Worker&&)' Worker worker_threads = Worker(4);" - 两者都解释了为什么你不能这样写。总之,你需要Worker worker_threads(4); IMO 此处的诊断错误。您为Worker 提供了复制构造函数,因此您还应该按照the Rule of Five 提供移动构造函数(和赋值运算符) @Yksisarvinen 我不会称之为,它太正式了。但是 IMO 解释五规则并不是编译器的主要工作 实例化一个类使用Worker worker_threads(4);而不是Worker worker_threads = Worker(4); 【参考方案1】:

问题在于,您定义了一个复制构造函数。因此,您没有默认的移动构造器。

我看不出你怎么能有一个正确的复制构造函数,因为std::thread不能被复制,所以std::vector&lt;std::thread&gt;不能被复制。

默认移动构造函数应该适用于您的情况。

所以要明确添加以下行:

public:

   Worker(const Worker&) = delete;
   Worker& operator=(const Worker&) = delete;
   Worker(Worker&&) = default;
   Worker& operator=(Worker&&) = default;

到你的 Worker 类。

【讨论】:

以上是关于在不复制此变量或互斥变量的情况下访问类成员的主要内容,如果未能解决你的问题,请参考以下文章

在不事先了解特定成员函数的情况下从另一个类访问成员函数

面向对象三大特征--多态

在不使用朋友类的情况下访问私人成员[重复]

static关键字

static关键字

Java 内部类及其原理