In an XMLRPC server that I'm working on (based off xmlrpc-c) the threads may want to make a MySQL connection to retrieve some data, using the following function:
Distribution getEntitySetFromMysql( int id ) {
Distribution result;
try {
sql::Driver *driver = get_driver_instance();
sql::Connection *con = driver->connect( (std::string)DBHOST, (std::string)USER, (std::string)PASSWORD);
con->setSchema( (std::string)DATABASE );
sql::Statement *stmt = con->createStatement();
std::stringstream query;
query << "SELECT concept_id, weight FROM entity_set_lines WHERE entity_set_id = " << id;
sql::ResultSet *res = stmt->executeQuery ( query.str() );
while (res->next()) {
result[ res->getInt("concept_id") ] = res->getDouble("weight");
}
delete res;
delete stmt;
con->close();
delete con;
} catch (sql::SQLException &e) {
std::cout << "ERROR: SQLException in " << __FILE__;
std::cout << " (" << __func__<< ") on line " << __LINE__ << std::endl;
std::cout << "ERROR: " << e.what();
std::cout << " (MySQL error code: " << e.getErrorCode();
std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;
if (e.getErrorCode() == 1047) {
std::cout << "\nYour server does not seem to support Prepared Statements at all. ";
std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
}
} catch (std::runtime_error &e) {
std::cout << "ERROR: runtime_error in " << __FILE__;
std::cout << " (" << __func__ << ") on line " << __LINE__ << std::endl;
std::cout << "ERROR: " << e.what() << std::endl;
}
return result;
}
All works fine, but after a thread runs this code and successfully returns its result, the thread remains hanging and does not exit. What is wrong with this approach? How fundamentaly wrong is this? Is the MySQL connector thread safe?
While Googling around for a solutions, I came across mentions of sql::Driver::threadInit() and sql::Driver::threadEnd(). However, as I was on version 1.0.5 of the C++ Connector, these functions were not available to me. Adding a driver->threadInit(); after getting a driver instance and driver->threadEnd(); at the end of my function, this problem was resolved.
The following is the mention of this thread init and end functionality in MySQL's 1.1.0 change history:
Added Driver::threadInit() and Driver::threadEnd() methods. Every
thread of a threaded client must call Driver::threadInit() at the very
start of the thread before it does anything else with Connector/C++
and every thread must call Driver::threadEnd() when it finishes. You
can find an example demonstrating the use in examples/pthreads.cpp. It
is strongly discouraged to share connections between threads. It is
theoretically possible, if you set certain (undocumented) mutexes, but
it is not supported at all. Use one connection per thread. Do not have
two threads using the same connection at the same time. Please check
the C API notes on threading on the MySQL manual. Connector/C++ wraps
the C API. (Lawrin, Andrey, Ulf)
TL;DR: If you come across this problem, make sure that your version of the C++ MySQL Connector is >= 1.1.0 and use the sql::Driver::threadInit() and sql::Driver::threadEnd() methods to surround your connection code.
Two thoughts:
libmysql isn't fully thread safe.
the way your code is structured you will leak memory if an exception occurs. you might be better served by either declaring your variables outside the try/catch and using a finally (or local equivalent) to ensure proper cleanup or using smart pointers (if available).
Since you don't show any of the calling or surrounding code it's hard to tell what's actually going on. Do you check the exit code of the thread when it's supposedly done? Can you attach it in a debugger to see what it's doing instead of closing?
Actually :
DO NOT USE : sql::Driver::threadInit() nor sql::Driver::threadEnd()
BECAUSE : you are already using try()
YOU FORGOT :
res->close();
stmt->close();
con->close();
delete res;
delete stmt;
delete con;
EXAMPLE :
int connection_and_query_func()
{
/*connection and query variables*/
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
int err_exception_getErrorCode=0;
/*results variables*/
int my_int_from_column_1 = 0;
double my_double_from_column_2 = 0;
....
std:string my_string_from_column_p = "";
try
{
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("address_name", "user_name", "password");
/* Connect to the MySQL database */
con->setSchema("schema_name");
/* Execute MySQL Query*/
stmt = con->createStatement();
res = stmt->executeQuery("your query statement here");
/* Read MySQL Query results per column*/
my_int_from_column_1 = res->getInt(1);
my_double_from_column_2 = res->getDouble(2);
....
my_string_from_column_p = res->getString(p);
/* Close MySQL Connection*/
res->close();
stmt->close();
con->close();
delete res;
delete stmt;
delete con;
};
/* Get last error*/
catch (sql::SQLException &exception)
{
err_exception_getErrorCode = exception.getErrorCode();
};
return(0);
};
CONCLUSION : this can be executed as many times as you want. The function example (connection_and_query_func()) will close MySQL connection properly after it is done - without adding up processes to your MySQL server!!!
FURTHERMORE : read the official manual https://docs.oracle.com/cd/E17952_01/connector-cpp-en/connector-cpp-en.pdf
ALTERNATIVE : if you cannot close properly your connection and query from your program/function side (thus adding up processes to your MySQL server) consider the 2 following options:
1/ set all MySQL timeout parameters to 10 sec. or less (for instance);
2/ write a script that SHOW PROCESSLIST and delete processes that are in SLEEP for too long.
Cheers.
Related
I was wondering if I could upload a file (with an mp3 extension) to MySQL Database.
I am using C++ for my application.
Thanks.
Turorial
You will need to create a database, and a table, the table needs to have the following columns.
[name] -> [column data type]
id -> PRIMARY INT AUTOINCREAMENTAL
filename -> vchar(255)
data -> TEXT
then use the example code below, and do an insert into this newly created table.
Guide
You will need to follow the MySQL Connector/C++ 8.0 Developer Guide
This manual describes how to install and configure MySQL Connector/C++ 8.0, which provides C++ and plain C interfaces for communicating with MySQL servers, and how to use Connector/C++ to develop database applications.
Requirements
Connector/C++ 8.0 is highly recommended for use with MySQL Server 8.0 and 5.7. Please upgrade to Connector/C++ 8.0.
Example code
/* Copyright 2008, 2010, Oracle and/or its affiliates.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
There are special exceptions to the terms and conditions of the GPL
as it is applied to this software. View the full text of the
exception in file EXCEPTIONS-CONNECTOR-C++ in the directory of this
software distribution.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Standard C++ includes */
#include <stdlib.h>
#include <iostream>
/*
Include directly the different
headers from cppconn/ and mysql_driver.h + mysql_util.h
(and mysql_connection.h). This will reduce your build time!
*/
#include "mysql_connection.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
using namespace std;
int main(void)
{
cout << endl;
cout << "Running 'SELECT 'Hello World!' »
AS _message'..." << endl;
try {
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("tcp://127.0.0.1:3306", "root", "root");
/* Connect to the MySQL test database */
con->setSchema("test");
stmt = con->createStatement();
res = stmt->executeQuery("SELECT 'Hello World!' AS _message");
while (res->next()) {
cout << "\t... MySQL replies: ";
/* Access column data by alias or column name */
cout << res->getString("_message") << endl;
cout << "\t... MySQL says it again: ";
/* Access column data by numeric offset, 1 is the first column */
cout << res->getString(1) << endl;
}
delete res;
delete stmt;
delete con;
} catch (sql::SQLException &e) {
cout << "# ERR: SQLException in " << __FILE__;
cout << "(" << __FUNCTION__ << ") on line " »
<< __LINE__ << endl;
cout << "# ERR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
}
cout << endl;
return EXIT_SUCCESS;
}
Suppose we have the following cuda code:
kernel1<<<blockGrid, threadBlock>>>(gpu_out, gpu_in, THREADS);
cerr << "a: " << cudaGetErrorString(cudaGetLastError()) << endl;
cudaDeviceSynchronize();
kernel2<<<blockGrid, threadBlock>>>(gpu_out2, gpu_out, gpu_in);
cerr << "b: " << cudaGetErrorString(cudaGetLastError()) << endl;
cudaDeviceSynchronize();
cout << "c " << endl;
I need gpu_out to be processed before continuing to the next kernel, and both kernels should do their work before executing the remaining cpu code.
Even though I included the cudaDeviceSynchronize() calls, the code does not run sequentially, since the output looks like this:
a: no error
c
b: no error
You're misinterpreting the output. Your code as written will execute sequentially.
Change all your stream I/O to use the same stream either cerr or cout, not both.
cerr and cout are buffered streams. That they don't flush to your console in any specific order is not related to the order of execution of calls writing to them. Try switching your output to cout to an output to cerr instead to see them ordered properly.
i got a strange probem with tesseract ocr. everything works fine, like the ocr part. characters are recognized correctly. but it crashes after it has done all calculations
this only happens when i run the code in a thread.
void server(boost::asio::io_service & io_service, unsigned short port)
{
tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
for (;;)
{
a.accept(sock);
//boost::thread t(session, boost::ref(sock));
//t.detach();
std::thread(session, std::move(sock)).detach();
}
}
void session(tcp::socket & sock)
{
tesseract::TessBaseAPI api;
if (api.Init("", "eng"))
{
fprintf(stderr, "Could not initialize tesseract.\n");
exit(1);
}
for (int i = 0; i < 81; i++)
{
if (!sudokuDatainside[i].empty())
{
api.SetImage((uchar*)sudokuDatainside[i].data, sudokuDatainside[i].size().width, sudokuDatainside[i].size().height, sudokuDatainside[i].channels(), sudokuDatainside[i].step1());
// Get OCR result
outText = api.GetUTF8Text();
std::cout << outText << std::endl;
}
else
{
std::cout << "Nothing - " << i << std::endl;
}
}
api.End();
}
Edit: seems its not a problem with api.End(). even if i dont call this method the programm crashes when the thread ends... does tesseract support threads?
After some hours of trying to find a solution. I came across an error during building the debug libs.
So rebuilding the tesseract debug libs solved the problem.
Here are the instructions i used:
https://github.com/charlesw/tesseract-vs2012
I'm very new in quickfix.
I created a client that connects normally with server. On my fromApp() function I can print the message with a simple std::cout << message << std::endl; and all fields of the message are there, also they are there on log files. When I try to call crack() it throws Field not found exception. Looking at log files I saw that the exception is thrown because quickfix can't find field 35. Anyone knows something about this?
EDIT1:
void fromApp( const FIX::Message& message,
const FIX::SessionID& sessionID )
throw( FIX::FieldNotFound, FIX::IncorrectDataFormat, FIX::IncorrectTagValue, FIX::UnsupportedMessageType )
{
std::cout << "FromApp" << std::endl;
std::cout << message << std::endl;
try
{
crack( message, sessionID );
}
catch(std::exception& ex)
{
std::cout << "crack exception: " << ex.what() << std::endl;
}
}
void onMessage( const FIX44::MarketDataIncrementalRefresh& message, const FIX::SessionID& sessionID )
{
std::cout << "OnMessage" << std::endl;
}
On my terminal windows I get the following output:
FromApp
8=FIX.4.49=12335=W34=7249=servidor52=20150123-13:34:56.95756=cliente22=448=CERB001D55=CERB001D268=1269=0270=100271=1000290=110=239
crack exception: Field not found
On the the message.current.log I get:
20150123-13:29:03.618 : 8=FIX.4.49=7035=A34=149=cliente52=20150123-13:29:03.61856=servidor98=0108=2010=077
20150123-13:29:03.655 : 8=FIX.4.49=7035=A34=149=servidor52=20150123-13:29:03.65856=cliente98=0108=2010=081
20150123-13:29:06.629 : 8=FIX.4.49=12235=W34=249=servidor52=20150123-13:29:06.63556=cliente22=448=CERB001D55=CERB001D268=1269=0270=100271=1000290=110=175
EDIT2:
When I put the crack() function outside the try-catch block, in message.event.log I get:
20150123-15:49:11.204 : Message 2 Rejected: Conditionally Required Field Missing:35
20150123-15:49:16.221 : Message 3 Rejected: Conditionally Required Field Missing:35
Thank you in advance.
I finally found the source of the problem.
I had installed quickfix from source code and it seems that in newer versions of quickfix (1.14.0 and latest) something changed in DataDictionaryProvadider.h related with shared pointers and it seems that it was the cause of the problem. When I installed quickfix from apt-get, I got version 1.13.3 and everything worked fine.
Thanks to everybody who tried to help.
in my Qt (4.8.1) based application I need to retrieve the definition of a view stored in a MySql database.
The code I'm using is
QSqlQuery query;
query.prepare(QString("SHOW CREATE VIEW %1").arg(viewName));
qDebug() << "actually sending this query: " << query.lastQuery();
qDebug() << "exec retuned " << query.exec();
qDebug() << "last error reported as " << query.lastError();
qDebug() << "size = " << query.size();
qDebug() << "numRowsAffected" << query.numRowsAffected();
QString viewCreateString;
if (query.first()) {
viewCreateString = query.value(1).toString();
qDebug() << "got this create view record" << viewCreateString;
}
When I run the above code I get the following result:
actually sending this query: "SHOW CREATE VIEW AC_STATE_V"
exec retuned true
last error reported as QSqlError(-1, "", "")
size = -1
numRowsAffected -1
Note that:
if I run the very same (cut&paste) command from within a MySql Workbench SQLTab connected to the same DB using the same credentials I do get the expected results (i.e.view exists and user got sufficient rights to retrieve it)
all of the above is also valid for a TABLE