Я тестирую потоки 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
}
}
Проблема в том, что threadLoop
является функцией-членом, но нет объекта для его применения. Просто угадаю
std::thread connectionThread(&Connection::threadLoop, this);
Но это только синтаксическая проблема; также есть логическая проблема: эта строка создает локальный объект типа std::thread
это уходит, когда функция возвращается. Его деструктор назовет std::terminate()
потому что поток не был присоединен. Скорее всего, это должно было присоединить поток к connectionThread
член. Для этого:
std::thread thr(threadLoop, this);
std::swap(thr, connectionThread);
У вашего кода есть две проблемы:
std::thread
конструктор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
Объект окончательно уничтожен, основной поток будет ждать завершения дополнительного потока (при необходимости), а затем продолжится нормальное выполнение. Я надеюсь, что это то, что вы хотели достичь с помощью своего кода.
Как вы можете извлечь из cppreference, std::thread
конструктор ожидает некоторую форму функции; вы можете передать ему свободную функцию, статическую функцию-член или одну из них, упакованную вместе с ее аргументами, с помощью std::bind
. Для выполнения нестатической функции-члена вы должны использовать std::mem_fn
чтобы передать его вместе с объектом, он должен быть вызван.