天天看點

mysql_init調用卡住原因分析

mysql_init調用卡住原因分析

有同學做類似如下的操作:

class X

{

public:

X() // 類X的構造函數ctor

_mysql_handler = mysql_init(NULL);

}

};

// 定義類X的全局變量

X g_x;

// 程式入口main函數

int main()

。。。 。。。

看似簡單的代碼,但非常不幸,程式運作時,卡在了mysql_init處。文法上看不出任何破綻,原因會是什麼了?

#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;

  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: 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())

    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);

      if ((env= getenv("MYSQL_TCP_PORT")))

        mysql_port=(uint) atoi(env);

    if (!mysql_unix_port)

#ifdef __WIN__

      mysql_unix_port = (char*) MYSQL_NAMEDPIPE;

#else

      mysql_unix_port = (char*) MYSQL_UNIX_ADDR;

      if ((env = getenv("MYSQL_UNIX_PORT")))

mysql_unix_port = env;

    mysql_debug(NullS);

#if defined(SIGPIPE) && !defined(__WIN__)

    (void) signal(SIGPIPE, SIG_IGN);

#ifdef EMBEDDED_LIBRARY

    if (argc > -1)

       result= init_embedded_server(argc, argv, groups);

    result= (int)my_thread_init();         /* Init if new thread */

  return result;

繼續閱讀