#c #multithreading #libmysql #connection-pool
#c #многопоточность #libmysql #пул соединений
Вопрос:
Мой код выглядит следующим образом:
main.cc
int main(void){
int port, sqlPort, ConnectionNum, threadNum;
string sqlUser, sqlPwd, DBName;
try{
Config Settings("./config.ini");
Settings.Read("port",port);
Settings.Read("sqlPort",sqlPort);
Settings.Read("sqlUser",sqlUser);
Settings.Read("sqlPwd",sqlPwd);
Settings.Read("DBName",DBName);
Settings.Read("ConnectionNum",ConnectionNum);
Settings.Read("threadNum",threadNum);
}catch(File_Not_Foundamp; e){
cerr << "Cannot Find the Configuration File:" << e.what() << endl;
exit(1);
}catch(Key_Not_Foundamp; e){
cerr << "Cannot Find the Keyword:" << e.what() << endl;
exit(1);
}
WebServer server(port, 5000, sqlPort, sqlUser, sqlPwd,DBName, ConnectionNum, threadNum );
//server.Start();
return 0;
}
WebServer.cc
WebServer::WebServer(int port, int timeoutMS, int sqlPort,
const std::stringamp; sqlUser, const std::stringamp; sqlPwd,
const std::stringamp; dbName, int connPoolNum, int threadNum)
:m_port(port), m_timeoutMS(timeoutMS),
m_epoller(new Epoller()),m_timer(new TimerHeap()){
assert(port < 65535 amp;amp; port > 1024);
m_srcDir = get_current_dir_name();
assert(m_srcDir);
strncat(m_srcDir, "/resources/", 16);
HttpConn::userCnt = 0;
HttpConn::srcDir = m_srcDir;
connPool->init("localhost", sqlUser, sqlPwd, dbName, sqlPort, connPoolNum);
threadPool->start(threadNum);
m_isRunning = InitSocket();
if(m_isRunning){
LOG_INFO << "===================== Server Init Success =====================";
LOG_INFO << "Port : " << m_port << ", srcDir :" << m_srcDir;
LOG_INFO << "threadNum : " << threadNum << ", ConnectionNum : " << connPoolNum;
}else{
LOG_FATAL << "Socket Init Failure";
}
}
SqlConnectionPool.cc
ConnectionPool *ConnectionPool::GetInstance()
{
static ConnectionPool connPool;
return amp;connPool;
}
void ConnectionPool::init(string url, string User, string PassWord, string DBName, int Port, int MaxConn)
{
m_url = url;
m_Port = Port;
m_User = User;
m_PassWord = PassWord;
m_DatabaseName = DBName;
for (int i = 0; i < MaxConn; i )
{
MYSQL *con = NULL;
con = mysql_init(con); //segmentation fault happened!!
if (con == NULL)
{
LOG_FATAL << "MySQL Init Error";
}
con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);
if (con == NULL)
{
LOG_FATAL << "MySQL Get Real Connection Error";
}
connList.push_back(con);
m_FreeConn;
}
m_MaxConn = m_FreeConn;
}
Как показано на рисунке выше, указатель con всегда равен nullptr, и это приводит к ошибке сегментации. И я пишу другой код для тестирования SqlConnectionPool.cc файл, но на этот раз он работает отлично.
SqlConnectionPool_test.cc (часть кода)
ConnectionPool* connPool = ConnectionPool::GetInstance();
unordered_map<string, string> users;
vector<thread> thread_pool;
int main(void){
connPool->init("localhost", "root", "123123", "zjwdb", 3306, 8);
{
MYSQL *mysql = NULL;
connectionRAII mysqlcon(amp;mysql, connPool);
if(mysql_query(mysql, "CREATE TABLE user_test(username VARCHAR(100) NOT NULL,passwd VARCHAR(60) NOT NULL,PRIMARY KEY ( username ));")){
LOG_ERROR << "CREATE TABLE user_test Failed : " << mysql_error(mysql);
}
if(!Register("test1", "test1")){
LOG_ERROR << "INSERT test user Failed";
}
if(!Register("test2", "test2")){
LOG_ERROR << "INSERT test user Failed";
}
if(!Register("test3", "test3")){
LOG_ERROR << "INSERT test user Failed";
}
showUsers(mysql);
}
CountDownLatch latch(4);
thread_pool.emplace_back(login, "test1", "test1");
thread_pool.emplace_back(login, "test5", "test5");
thread_pool.emplace_back(login, "test1", "test");
thread_pool.emplace_back([](CountDownLatchamp; latch, string constamp; name, string constamp; passwd)
{
latch.countDown();
latch.wait();
Register(name, passwd);
login(name, passwd);
}
, std::ref(latch), "test_user1", "123123");
thread_pool.emplace_back([](CountDownLatchamp; latch, string constamp; name, string constamp; passwd)
{
latch.countDown();
latch.wait();
Register(name, passwd);
login(name, passwd);
}
, std::ref(latch), "test_user2", "123123");
thread_pool.emplace_back([](CountDownLatchamp; latch, string constamp; name, string constamp; passwd)
{
latch.countDown();
latch.wait();
Register(name, passwd);
login(name, passwd);
}
, std::ref(latch), "test_user3", "123123");
thread_pool.emplace_back([](CountDownLatchamp; latch, string constamp; name, string constamp; passwd)
{
latch.countDown();
latch.wait();
Register(name, passwd);
login(name, passwd);
}
, std::ref(latch), "test3", "test3");
for(autoamp; th : thread_pool){
if(th.joinable())
th.join();
}
MYSQL* conn_temp = NULL;
connectionRAII mysqlconn_temp(amp;conn_temp, connPool);
showUsers(conn_temp);
dropTheTable();
return 0;
}
Это действительно меня смущает. Это ошибка libmysql.lib?? Если это так, как я должен это исправить?
PS:
- Моя версия Ubuntu — Ubuntu-16.04, а версия lib — libmysqlclient.so.20.
- SqlConnectionPool_test.cc выполняется в многопоточной среде. Причина в том, что этот тестовый файл с большей вероятностью завершится сбоем, потому что mysql_init не является потокобезопасным. Но это может работать отлично.
- Пожалуйста, дайте мне знать, если вам нужна дополнительная информация, спасибо!
Комментарии:
1. Что такое
connPool
? Вы продолжаете использовать эту переменную, но не показываете, как она инициализируется2. Вы получили ошибку segfault изнутри malloc , это означает, что у вас проблема с повреждением памяти. Попробуйте использовать valgrind для его отладки.
3. @UnholySheep SqlConnectionPool является синглтоном. connPool является указателем на экземпляр SqlConnectionPool . Для инициализации используется метод инициализации SqlConnectionPool . « SqlConnectionPool *connPool = SqlConnectionPool::getInstance(); «
4. @user253751 Хорошо, спасибо! Я попробую.
5. Я решил свою проблему. Причиной ошибки сегментации была функция get_current_dir_name, а не mysql_init. Функция get_current_dir_name выделила память, которая как раз соответствовала текущему имени каталога, для переменной m_srcDir , . И я использовал strncat для подключения m_srcDir и «resource», а затем произошла ошибка сегментации.