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之后有很多文章都告诉你解决方法,但是很少有文章分析为什么会慢,这篇文章 ...
随机推荐
- win7 安装过程中遇到的错误解决方法
win7 安装过程中遇到的错误解决方法 windows安装无法继续.若要安装windows 请单击 确定 重新启动计算机: 当 出现如上提示的时候,按下shift+f10 会打开命令窗口,进入到C:\ ...
- simple_one_for_one 和 one_for_one的区别
参考这里http://blog.sina.com.cn/s/blog_77cb45a70102v1ja.html 用起来最直观的不同点 simple_one_for_one需要手工start_chil ...
- Linux机器工作环境安装
安装gcc编译器: yum -y install gcc 安装wget: yum -y install wget 安装python-setuptools: wget http://peak.telec ...
- 前端自动化之npm
npm——node依赖包管理工具 安装: 1.在nvm目录下复制npm和npm-cath文件夹 2.配置环境变量. 使用: 1.在项目文件夹,shift+右键打开命令窗口 2.npm init ...
- Halcon学习(八)文本操作
标签: 学习 杂谈 分类: halcon学习 1.open_file( : : FileName, FileType : FileHandle) FileType: 'output':创建文本 ‘ap ...
- JQuery UI Datepicker中文显示的方法
出自:http://www.aimks.com/method-to-display-the-jquery-ui-datepicker-chinese.html Query UI Datepicker这 ...
- 13-EasyNetQ之发布者确认
AMQP发布消息默认情况下是非事务性的,不能确保你的消息真正送达代理.AMQP可以去指定事务性发布,但是RabbitMQ这样会非常慢,我们没有让EasyNetQ API去支持此功能.为了高效的确保投递 ...
- cacti启动有图无数据
cactiEZ服务器重启后,获取不到图形的解决办法 cd /var/www/html/cli/ php -q rebuild_poller_cache.php -d myisamchk --safe- ...
- 强大的HTML5开发工具推荐
HTML5被看做是Web开发者创建流行Web应用的利器,增加了对视频和Canvas 2D的支持.HTML5的诞生还让人们重新审视浏览器专用多媒体插件的未来,如Adobe的Flash和微软的Silver ...
- python 生成器的理解和总结
1. 生成器 利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成.但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数 ...