mysql_init调用卡住原因分析
有同学做类似如下的操作:
|
class X { public: X() // 类X的构造函数ctor { _mysql_handler = mysql_init(NULL); } // 定义类X的全局变量 X g_x; // 程序入口main函数 int main() { 。。。 。。。 } |
看似简单的代码,但非常不幸,程序运行时,卡在了mysql_init处。语法上看不出任何破绽,原因会是什么了?
他提供了另一个线索:不在构造函数中调用mysql_init则正常,不会卡住。结合起来分析,推断是因为mysql_init中也使用到了全局变量(另一种原因是有越界),而全局变量的初始化顺序程序是无法约定的,很有可能是因为g_x的初始化,发生在mysql_init依赖的全局变量之前。若推论成立,则mysql_init使用了未初始化的值,这是导致它卡住的根本原因。可以使用valgrind验证一下。当然,使用下列的方法应当也能奏效:全局变量相互依赖和初始化顺序的解决办法(http://blog.chinaunix.net/uid-20682147-id-3245149.html),即改成:
|
#define g_x x_ref() X& x_ref() { static X x; // 技巧就在这里 return x; } |
当然,良好的习惯是尽量避免使用全局变量,实在无法避免时(如考虑到结构的复杂性),则可以考虑用上述方法规避全局变量互依赖产生的问题。
附1:mysql_init源码
|
/**************************************************************************** Init MySQL structure or allocate one ****************************************************************************/ MYSQL * STDCALL mysql_init(MYSQL *mysql) { if (mysql_server_init(0, NULL, NULL)) return 0; if (!mysql) { if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL)))) { set_mysql_error(NULL, CR_OUT_OF_MEMORY, unknown_sqlstate); return 0; } mysql->free_me=1; } else memset(mysql, 0, sizeof(*(mysql))); mysql->charset=default_client_charset_info; strmov(mysql->net.sqlstate, not_error_sqlstate); /* Only enable LOAD DATA INFILE by default if configured with --enable-local-infile */ #if defined(ENABLED_LOCAL_INFILE) && !defined(MYSQL_SERVER) mysql->options.client_flag|= CLIENT_LOCAL_FILES; #endif #ifdef HAVE_SMEM mysql->options.shared_memory_base_name= (char*) def_shared_memory_base_name; #endif mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION; mysql->options.report_data_truncation= TRUE; /* default */ /* By default we don't reconnect because it could silently corrupt data (after reconnection you potentially lose table locks, user variables, session variables (transactions but they are specifically dealt with in mysql_reconnect()). This is a change: < 5.0.3 mysql->reconnect was set to 1 by default. How this change impacts existing apps: - existing apps which relyed on the default will see a behaviour change; they will have to set reconnect=1 after mysql_real_connect(). - existing apps which explicitely asked for reconnection (the only way they could do it was by setting mysql.reconnect to 1 after mysql_real_connect()) will not see a behaviour change. - existing apps which explicitely asked for no reconnection (mysql.reconnect=0) will not see a behaviour change. */ mysql->reconnect= 0; mysql->options.secure_auth= TRUE; return mysql; } |
附2:mysql_server_init源码
|
/* Initialize the MySQL client library SYNOPSIS mysql_server_init() NOTES Should be called before doing any other calls to the MySQL client library to initialize thread specific variables etc. It's called by mysql_init() to ensure that things will work for old not threaded applications that doesn't call mysql_server_init() directly. RETURN 0 ok 1 could not initialize environment (out of memory or thread keys) */ int STDCALL mysql_server_init(int argc __attribute__((unused)), char **argv __attribute__((unused)), char **groups __attribute__((unused))) { int result= 0; if (!mysql_client_init) { mysql_client_init=1; org_my_init_done=my_init_done; if (my_init()) /* Will init threads */ return 1; init_client_errs(); if (mysql_client_plugin_init()) return 1; if (!mysql_port) { char *env; struct servent *serv_ptr __attribute__((unused)); mysql_port = MYSQL_PORT; /* if builder specifically requested a default port, use that (even if it coincides with our factory default). only if they didn't do we check /etc/services (and, failing on that, fall back to the factory default of 3306). either default can be overridden by the environment variable MYSQL_TCP_PORT, which in turn can be overridden with command line options. */ #if MYSQL_PORT_DEFAULT == 0 if ((serv_ptr= getservbyname("mysql", "tcp"))) mysql_port= (uint) ntohs((ushort) serv_ptr->s_port); #endif if ((env= getenv("MYSQL_TCP_PORT"))) mysql_port=(uint) atoi(env); } if (!mysql_unix_port) { char *env; #ifdef __WIN__ mysql_unix_port = (char*) MYSQL_NAMEDPIPE; #else mysql_unix_port = (char*) MYSQL_UNIX_ADDR; #endif if ((env = getenv("MYSQL_UNIX_PORT"))) mysql_unix_port = env; } mysql_debug(NullS); #if defined(SIGPIPE) && !defined(__WIN__) (void) signal(SIGPIPE, SIG_IGN); #endif #ifdef EMBEDDED_LIBRARY if (argc > -1) result= init_embedded_server(argc, argv, groups); #endif } else result= (int)my_thread_init(); /* Init if new thread */ return result; } |
mysql_init调用卡住原因分析的更多相关文章
- Nodejs通过Thrift操作hbase卡住原因分析及与javascript的垃圾回收机制的关系
在最近使用Nodejs通过Thrift操作hbase的时候写了个脚本,不断发送http请求,从而取得hbase下所需的数据,但是在run的过程中for循环并没有执行完全,在执行一部分后会卡住,就再也进 ...
- Pycharm下同一目录的py文件不能相互调用的原因分析
1.首先确保所在目录是Python Package而不是一般的New Stratch File Python Package下有__init___.py或自己建空的__init___.py 2.pyc ...
- android ListView 在初始化时多次调用getView()原因分析
今天在做一个功能:在初始化ListView时,把第一行背景置为黄色,同时保存第一行对象,用于在点击其他行时将该行重新置为白色. if(position==0){ convertView.setBack ...
- VC++ MFC单文档应用程序SDI下调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错原因分析及解决办法:glewInit()初始化的错误
1.问题症状 在VC++环境下,利用MFC单文档应用程序SDI下开发OpenGL程序,当调用glGenBuffersARB(1, &pbo)方法编译通过但执行时出错,出错代码如下: OpenG ...
- Beforeunload打点丢失原因分析及解决方案
淘宝的鱼相在 2012 年 8 月份发表了一篇文章,里面讲述了他们通过一个月的数据采集试验,得到的结果是:如果在浏览器的本页面刷新之前发送打点请求,各浏览器都有不同程度的点击丢失情况,具体点击丢失率统 ...
- Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析
原文:Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析 前段时间,公司同事开发了一个小工具,在工具执行过程中,UI界面一直处于卡死状态. 通过阅读代码发现,主要是 ...
- 修改List报ConcurrentModificationException异常原因分析
使用迭代器遍历List的时候修改List报ConcurrentModificationException异常原因分析 在使用Iterator来迭代遍历List的时候如果修改该List对象,则会报jav ...
- iOS学习——内存泄漏检查及原因分析
项目的代码很多,前两天老大突然跟我说项目中某一个ViewController的dealloc()方法没有被调用,存在内存泄漏问题,需要排查原因,解决内存泄漏问题.由于刚加入项目组不久,对出问题的模块的 ...
- Linux ssh登陆慢的两种原因分析
Linux ssh登陆慢的两种原因分析 如果做运维就一定会遇到ssh登陆Linux服务器慢的问题,问题比较好解决,一般Google之后有很多文章都告诉你解决方法,但是很少有文章分析为什么会慢,这篇文章 ...
随机推荐
- Java 数组的定义和遍历
1.一维数组 数组是用来存储一组相同数据类型数据的数据结构 数组的元素可以是简单数据类型的数据,也可以是引用数据类型的数据 无论数组内容是简单类型还是引用类型,数组自己本身都是一种引用类型 每个数组元 ...
- Linux bash shell 入门
https://www.cnblogs.com/cosiray/archive/2012/03/02/2377099.html
- sublime 工具
http://blog.csdn.net/admin_yi/article/details/53608965
- python urllib和urllib3包
urllib.request urllib当中使用最多的模块,涉及请求,响应,浏览器模拟,代理,cookie等功能. 1. 快速请求 urlopen返回对象提供一些基本方法: read 返回文本数据 ...
- (转)Oracle存储过程基本语法
本文转载自:http://www.cnblogs.com/hero4china/articles/base_rule_oracle_procedure.html 存储过程 1 CREATE OR R ...
- MySQL-事务的实现-redo
MySQL中事务: 事务的实现: ACID: 原子性(A : Atomicity) 一致性(C : consistency ) 隔离性(I : isolation) 持久性(D : dura ...
- python开发socket套接字:套接字&通信循环&链接循环&模拟远程命令
一,套接字 先从服务器端说起.服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接.在这时如果有个客户端初始化一个Socket ...
- PCB上 如何显示 汉字
原理图上有汉字,那如何在PCB上显示汉子呢 ? 而不至于显示乱码 按如下操作 ,双击乱码 ,进入设置模式 设置好后,显示的字体样式.
- Linux日志文件查看和搜查命令(错误日志排查定位)
一.cat命令 cat 命令用于连接文件并打印到标准输出设备上,主要用来查看文件内容,创建文件,文件合并,追加文件内容等功能. 语法格式 cat [-AbeEnstTuv] fileName 参数说明 ...
- 使用Selenium登录新浪微博
为了总结一下Selenium的用法,具体用了这个例子来说明一下. Selenium简单来说,就是通过程序驱动一个浏览器,并且可以通过程序来帮你做一些事情,例如点击.填表呀之类的. 换句话说,你在浏览器 ...