std :: thread () и std :: ref () вызывают ошибки сборки при использовании внутри класса - PullRequest
0 голосов
/ 22 февраля 2019

Я вчера отправил вопрос, но у меня не было работоспособного примера, чтобы дать другим пользователям.Я делаю сейчас, поэтому я удалил свой старый пост.

У меня есть код, который не удается собрать, когда я пытаюсь создать и использовать std::threads() и std::ref() внутри класса.Я не понимаю сообщения об ошибках, которые появляются, все они начинаются со строки error: no matching function for call или error: no type named ‘type’.

Я использую Clion и CMake, если это имеет значение.Моя файловая структура:

Personal
--include
----main.h
--src
----main.cpp
----CMakeLists.txt
--CMakeLists.txt

CMakeLists.txt

# CMAKE version requirement
cmake_minimum_required(VERSION 3.12)

# Project name
project(scrap CXX)

# Configure the build
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)
add_compile_options(-W -Wall -ggdb)
include_directories(include)
include_directories(${CMAKE_SOURCE_DIR}/include)

# What is being built
add_executable(scrap)
add_subdirectory(src)

# Add external dependencies
find_package(Threads REQUIRED)
target_link_libraries(scrap ${CMAKE_THREAD_LIBS_INIT})

src / CMakeLists.txt

# Add targets
target_sources(scrap PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
        )

main.h

#ifndef PERSONAL_MAIN_H
#define PERSONAL_MAIN_H

#include <future>
#include <iostream>
#include <unistd.h>

class ScrapPaper
{
public:
    ScrapPaper();
    static void SpinUpThreads();
    void ThreadFunction1(std::promise<bool> &prom);
    void ThreadFunction2(std::promise<bool> &prom);

private:

};

#endif //PERSONAL_MAIN_H

main.cpp

#include "../include/main.h"

using namespace std;

void ScrapPaper::ThreadFunction1(promise<bool> &prom)
{
    cout << "Thread " << this_thread::get_id() << " working in ThreadFunction1!" << endl;
    sleep(10);

    cout << "Thread " << this_thread::get_id() << " finished sleeping in Function1" << endl;
    prom.set_value_at_thread_exit(true);
}

void ScrapPaper::ThreadFunction2(promise<bool> &prom)
{
    cout << "Thread " << this_thread::get_id() << " working in ThreadFunction2!" << endl;
    sleep(2);
    cout << "Thread " << this_thread::get_id() << " finished sleeping in Function2" << endl;
    prom.set_value_at_thread_exit(true);
}

void ScrapPaper::SpinUpThreads()
{
    promise<bool> promise1;
    future<bool> future1 = promise1.get_future();
    std::thread (&ScrapPaper::ThreadFunction1, ref(promise1)).detach();

    promise<bool> promise2;
    future<bool> future2 = promise2.get_future();
    std::thread (&ScrapPaper::ThreadFunction2, ref(promise2)).detach();

    if (future1.get() && future2.get())
    {
        cout << "Everything was a-okay" << endl;
    }
    else
    {
        cout << "Whoops, there was an error..." << endl;
    }
}

int main(int argc, char *argv[])
{
    cout << "In Main..." << endl;
    ScrapPaper::SpinUpThreads();

} // end main

Вот некоторые ошибки, которые я получаю:

error: no matching function for call to ‘std::thread::_Invoker<std::tuple<void (ScrapPaper::*)(std::promise<bool>&), std::reference_wrapper<std::promise<bool> > > >::_M_invoke(std::thread::_Invoker<std::tuple<void (ScrapPaper::*)(std::promise<bool>&), std::reference_wrapper<std::promise<bool> > > >::_Indices)’
  operator()()
  ^~~~~~~~

и

error: no type named ‘type’ in ‘struct std::__invoke_result<void (ScrapPaper::*)(std::promise<bool>&), std::reference_wrapper<std::promise<bool> > >’

Когда класс убирают и остается только main() и ThreadFunction1(...) и ThreadFunction2(...), код создается и запускается.У меня проблема с объемом?Любой совет или помощь с благодарностью!

Ответы [ 3 ]

0 голосов
/ 22 февраля 2019

Проблема здесь в том, что, поскольку вы используете функции-члены, вам нужен экземпляр класса для вызова функций-членов.Если SpinUpThreads не был статическим, вы могли бы использовать

std::thread (&ScrapPaper::ThreadFunction1, this, ref(promise1)).detach();
std::thread (&ScrapPaper::ThreadFunction2, this, ref(promise2)).detach();

, но, поскольку он статический, вы должны создать экземпляр класса для передачи в конструктор thread s.Вы можете совместно использовать один объект для обоих вызовов или дать каждому потоку свой собственный объект.Это выглядит как

ScrapPaper common;
std::thread (&ScrapPaper::ThreadFunction1, common, ref(promise1)).detach();
std::thread (&ScrapPaper::ThreadFunction2, common, ref(promise2)).detach();

//or

std::thread (&ScrapPaper::ThreadFunction1, ScrapPaper{}, ref(promise1)).detach();
std::thread (&ScrapPaper::ThreadFunction2, ScrapPaper{}, ref(promise2)).detach();

Вы также можете использовать лямбду, чтобы упростить синтаксис вызова.Если вы используете лямбду, вы можете написать вызов функции более естественным образом, и это будет выглядеть как

ScrapPaper common;
std::thread ([&](){ common.ThreadFunction1(promise1); }).detach();
std::thread ([&](){ common.ThreadFunction2(promise2); }).detach();

//or

std::thread ([&](){ ScrapPaper{}.ThreadFunction1(promise1); }).detach();
std::thread ([&](){ ScrapPaper{}.ThreadFunction2(promise2); }).detach();
0 голосов
/ 22 февраля 2019

Вы можете сделать одну из двух вещей.Как написано, две функции потока являются нестатическими функциями-членами.У вас должен быть объект для их вызова, и это то, к чему обращались другие ответы.

Но ни одна из этих функций не использует никаких данных из объекта ScrapPaper, поэтому вы можете изменить их на static функции-члены и остальная часть вашего кода должны работать без изменений.То есть, измените

class ScrapPaper
{
public:
    ScrapPaper();
    static void SpinUpThreads();
    void ThreadFunction1(std::promise<bool> &prom);
    void ThreadFunction2(std::promise<bool> &prom);

private:

};

на

class ScrapPaper
{
public:
    ScrapPaper();
    static void SpinUpThreads();
    static void ThreadFunction1(std::promise<bool> &prom);
    static void ThreadFunction2(std::promise<bool> &prom);

private:

};

Конечно, с этими изменениями естественный вопрос состоит в том, почему ScrapPaper является классом, поскольку у него нет данных и нет объекта-специфичное поведение.Это предполагает, что возможно сделать ScrapPaper пространством имен, а не классом.Но это тема для другого вопроса.

0 голосов
/ 22 февраля 2019

При использовании std::thread для вызова функции-члена второй аргумент должен быть экземпляром класса (или указателем на него).

В вашем случае код будет

 static ScrapPaper p;
 std::thread (&ScrapPaper::ThreadFunction2, p, ref(promise2)).detach();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...