C ++ 11 std :: thread, выдающий ошибку: нет подходящей функции для вызова std :: thread :: thread

Я тестирую потоки c ++ 11 с этим кодом, но при создании потока у меня появляется ошибка нет подходящей функции для вызова std :: thread :: thread ().

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

Заголовок:

#ifndef CONNECTION_H
#define CONNECTION_H

#include <thread>
#include <mysql++.h>

class Connection
{
public:
Connection(std::string mysqlUser, std::string mysqlPassword);
~Connection();

private:
std::string mysqlUser;
std::string mysqlPassword;
std::string mysqlIP;
int mysqlPort;

mysqlpp::Connection mysqlConnection;
std::thread connectionThread;

void threadLoop();
};

#endif // CONNECTION_H

Источник:

#include "connection.h"
Connection::Connection(std::string mysqlUser, std::string mysqlPassword)
{
this->mysqlUser     = mysqlUser;
this->mysqlPassword = mysqlPassword;
this->mysqlIP       = "localhost";    //default
this->mysqlPort     = 3306;           //default

//Launch thread
std::thread connectionThread(threadLoop);

}

Connection::~Connection(){
mysqlConnection.disconnect();
}

void Connection::threadLoop(){
//Connect to mySQL database
mysqlConnection = new mysqlpp::Connection(false);

if(mysqlConnection.connect(NULL, mysqlIP.c_str(), mysqlUser.c_str(), mysqlPassword.c_str(), mysqlPort)){
std::string consulta = "SELECT * FROM 'Coordinates'";
mysqlpp::Query query = mysqlConnection.query(consulta);
mysqlpp::StoreQueryResult res = query.store();
query.reset();

}

while(true){
// Stuff
}
}

3

Решение

Проблема в том, что threadLoop является функцией-членом, но нет объекта для его применения. Просто угадаю

std::thread connectionThread(&Connection::threadLoop, this);

Но это только синтаксическая проблема; также есть логическая проблема: эта строка создает локальный объект типа std::thread это уходит, когда функция возвращается. Его деструктор назовет std::terminate() потому что поток не был присоединен. Скорее всего, это должно было присоединить поток к connectionThread член. Для этого:

std::thread thr(threadLoop, this);
std::swap(thr, connectionThread);
9

Другие решения

У вашего кода есть две проблемы:

  1. Вы предоставляете неполную информацию std::thread конструктор
  2. Вы уничтожаете std::thread прежде чем он соединяется с основным потоком.

Для первой проблемы, как Пит Беккер предлагает, вам нужно предоставить объект, для которого будет вызываться функция, потому что конструктор для std::thread нет другого способа узнать это. Предполагая, что вы хотите вызвать функцию threadLoop() на Connection Объект, который вы строите, вы можете сделать это:

//Launch thread
std::thread connectionThread(threadLoop, this);

Внутри конструктор вызовет this->threadLoop() (где this это Connection* параметр, который он получил, а не std::thread сам, конечно). И у тебя все будет хорошо.

Вторая проблема заключается в том, что ваш std::thread уничтожается сразу после запуска, не присоединяя его к основному потоку: это вызовет terminate(), что не очень хорошая вещь. Еще раз, Пит предлагает хорошую альтернативу. Замените приведенный выше код следующим:

// Launch thread
std::thread thr(threadLoop, this);
std::swap(thr, connectionThread);

Ситуация перед этим кодом выглядит следующим образом:

  • У вас есть тривиальный std::thread объект, connectionThread, который на самом деле не представляет поток

После выполнения первой строки кода:

  • У тебя все еще есть connectionThread
  • У вас также есть живая тема, представленная std::thread объект thr, который будет уничтожен в конце Connection конструктор, вызывая вызов terminate() потому что он никогда не присоединяется к основному потоку.

К счастью, на помощь приходит вторая строка кода. После выполнения этого:

  • У вас есть тривиальный std::thread, thr, который может быть безопасно уничтожен, потому что он не представляет реальный поток (поэтому он не присоединяется)
  • У вас есть живая тема, представленная connectionThreadобъект, который не будет уничтожен, пока Connection объект существует.

Теперь проблема в том, что вы хотите присоединиться connectionThread до основного потока, прежде чем он будет уничтожен, но вы также хотите избежать блокировки основного потока. Самое подходящее время для этого объединения — самое позднее время: когда connectionThread собирается быть уничтоженным. И это происходит в деструкторе Connection, Итак, мы добавим строку к этому деструктору следующим образом:

Connection::~Connection(){
mysqlConnection.disconnect();
connectionThread.join(); // Now connectionThread can be safely destroyed
}

Кроме того, это самое безопасное место, чтобы позвонить join()потому что это гарантирует, что вы никогда не уничтожите неприсоединившихся connectionThread, Это RAII в действии; Если вы не знакомы с концепцией RAII (или RIIA, как ее иногда называют), вы можете найти много информации об этой очень важной концепции в Интернете, включая этот сайт.

Все это воедино: создание Connection объект создаст новый поток; в этом потоке будет установлено новое соединение с базой данных, и будет выполнен запрос, в то время как основной поток остается свободным для любого другого использования (например, для управления графическим интерфейсом). Когда Connection Объект окончательно уничтожен, основной поток будет ждать завершения дополнительного потока (при необходимости), а затем продолжится нормальное выполнение. Я надеюсь, что это то, что вы хотели достичь с помощью своего кода.

4

Как вы можете извлечь из cppreference, std::threadконструктор ожидает некоторую форму функции; вы можете передать ему свободную функцию, статическую функцию-член или одну из них, упакованную вместе с ее аргументами, с помощью std::bind. Для выполнения нестатической функции-члена вы должны использовать std::mem_fn чтобы передать его вместе с объектом, он должен быть вызван.

2
По вопросам рекламы [email protected]