Доступ к членам класса без копирования этой переменной или переменной мьютекса - PullRequest
2 голосов
/ 17 февраля 2020

Я пытаюсь создать простой класс Worker, который будет создавать несколько потоков и набор задач для запуска потоков. Это познавательно, но я уже пытался спрашивать одноклассников и искать разные ответы, и я думаю, что здесь есть что-то «простое» / фундаментальное, которого я упускаю.

У меня есть некоторые проблемы относительно того, где должна быть установлена ​​моя переменная мьютекса. Я полагаю, что хотел бы один для каждого из моих объектов Worker, поскольку потоки, созданные каждым объектом, совершенно не связаны. Прямо сейчас я пытаюсь передать this лямбда-методу, который добавляет набор потоков, но он копирует мьютекс, который удаляет его. Есть ли способ скопировать каждого члена класса мне нужно независимо, или я должен создать конструктор копирования? Я только пытаюсь передать переменные класса мне нужно лямбда. Вот мой код:

// 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;
     ^~~~~

Спасибо за любые отзывы! Пожалуйста, укажите на любые глупые ошибки, которые я сделал, я просто пытаюсь изучить лучшие практики.

1 Ответ

4 голосов
/ 17 февраля 2020

Проблема была в том, что вы определили конструктор копирования. Поэтому у вас нет стандартного контура перемещения.

Я не вижу, как у вас может быть правильный конструктор копирования, поскольку std::thread не может быть скопирован, поэтому std::vector<std::thread> не может быть скопировано.

A default-move- Конструктор должен работать для вашего случая.

Таким образом, чтобы быть явным, добавьте строки:

public:

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

в ваш класс Worker.

...