Основываясь на документации Qt:
Соединение может использоваться только из потока, который его создал. Перемещение соединений между потоками или создание запросов из другого потока не поддерживается.
Вопрос, который меня беспокоит, - это то, что происходит при экземпляре базы данных copy-construct. Например, вот код в основном потоке:
int main(int argc, char** argv) {
...
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "DB1");
db.setHostName("localhost");
...
и вот соединение в рабочих потоках:
void MyThread::run() {
QSqlDatabase db(QSqlDatabase::database("DB1"));
if (db.open()) {
...
}
Является ли этот поток безопасным или нет? Как правило, такая операция была бы безопасной в С++, но поскольку QT использует неявный обмен и привязку потоков, я уже не уверен.
Говорят: соединение можно использовать только внутри потока, который его создал, но что это значит? Является QSqlDatabase:: addDatabase точкой, где создается соединение, или фактически, когда вызывается функция open().
UPDATE:
После ответа от Laszlo Papp и, в конечном счете, изучения исходного кода Qt, я должен сказать, что дизайн этой части Qt выглядит ошибочным для меня.
Если я правильно понимаю, QSqlDatabase использует неявный совлокальный доступ под капотом, но, к сожалению, это не истинный неявный совлокальный доступ, поскольку экземпляр-экземпляр экземпляра QSqlDatabase не создаст новый экземпляр общих данных, когда это необходимо. Чтобы ухудшить ситуацию, вы не можете создавать временное соединение, но вместо этого вы должны использовать статические методы addDatabase/removeDatabase, и в этом случае вам нужно синхронизировать потоки, чтобы избежать столкновения имен.
Это, конечно, делает очень сложным использование QSqlDatabase в QtConcurrent, особенно если соединение должно быть зарыто глубоко за некоторой абстракцией. Поскольку мы не знаем, по какому потоку код будет запущен, мы не сможем поддерживать соединение между двумя вызовами. И если мы хотим создать динамическое число задач, нам нужно будет убедиться, что задачи не используют одно и то же имя базы данных.
Все это заставляет меня задуматься о целях проектирования, и если неявное совместное использование подходит для этого конкретного случая. ИМХО, гораздо лучшим решением было бы позволить конструктору копирования действительно выполнять эту работу и сделать копию подключения для вас. Те, кто не хочет иметь личные/временные копии, все еще могут использовать addDatebase/removeDatabase, и в этом случае метод database() необходимо изменить для возврата ссылки.