多线程程序中的Mysql - my_thread_global_end()

问题描述 投票:0回答:3

我使用pthreads遇到了严重的mysql问题。结束我的程序后得到的错误:

“my_thread_global_end()出错:1个线程没有退出”

在启动任何线程之前,我在main中调用了mysql_library_init。为此,我刚刚开始了1个帖子。线程关闭后(使用pthread_join),我在main中调用mysql_library_end。在pthread本身我调用mysql_init。出于某种原因,这似乎是不正确的,因为我得到错误。我使用MySQL 5.6并与libmysqlclient.a链接。

mysql手册非常不清楚和矛盾,所以我希望有逻辑思维的人可以向我解释一下:

“在非多线程环境中,mysql_init会根据需要自动调用mysql_library_init。但是,mysql_library_init在多线程环境中不是线程安全的,因此也不是mysql_init。在调用mysql_init之前,要么在生成任何线程之前调用mysql_library_init,或者使用互斥锁来保护mysql_library_init调用。这应该在任何其他客户端库调用之前完成。“

第一行:所以mysql_init只在“需要时”在NONmulti-threaded环境中调用mysql_library_init(无论何时在NONmulti-threaded环境中都需要它?)因此我可以从中得知mysql_init()认为它不需要多线程环境?我猜不是,很好,我在我的主要调用mysql_library_init然后我到处读到我应该在线程之后调用mysql_init。我希望每个线程都有自己的连接,很好,我也这样做,所以每个线程都有自己的MYSQL结构。但手动sais mysql_init不是线程安全的...嗯,好吧......所以只用1个线程,我仍然有问题...

main -> mysql_library_init
main -> create 1 pthread
pthread -> mysql_init
pthread -> mysql_real_connect
pthread -> mysql_close
....

几秒后我按下Ctrl C(现在在线程中关闭了mysql),所以清理开始:

main -> pthread_cancel
main -> pthread_join
main -> mysql_library_end

结果:my_thread_global_end出错:1个线程没有退出

........

mysql c
3个回答
1
投票
int main( void )
{
   if ( mysql_library_init( 0, NULL, NULL ) != 0 ) { ... }
   if ( mysql_thread_safe() ) { ... } // This goes fine

   sem_init( &queue.totalStored, 0, 0 );
   pthread_mutex_init( &mutex_bees, NULL );
   pthread_create( &workerbees[tid], &attr, BeeWork, ( void * ) tid );
   pthread_attr_destroy( &attr );

   while ( recv_signal == 0 )
   {
      errno = 0;
      sock_c = accept( sock_s, NULL, NULL );

      if ( ( sock_c == -1 ) && ( errno == EINTR ) )
      {
         // do stuff
         if ( recv_signal == SIGHUP ) { /* do stuff*/ }
      } else { /* do stuff */ }
   }

   // CLEANUP
   close( sock_s );
   RC = pthread_cancel( workerbees[tid] );
   if ( RC != 0 ) { Log( L_ERR, "Unsuccessful pthread_cancel()" ); }

   // WAIT FOR THREADS TO FINISH WORK AND EXIT
   RC = pthread_join( workerbees[tid], &res );
   if ( RC != 0 ) { Log( L_ERR, "Error: Unsuccessful pthread_join()" ); }

   if ( res == PTHREAD_CANCELED )
   { /* print debug stuff */ }
   else { /* print debug stuff */ }

   mysql_library_end();
   sem_destroy( &queue.totalStored );
   exit( 0 );
}

void *BeeWork( void *t )
{
   // DISABLE SIGNALS THAT main() ALREADY LISTENS TO
   sigemptyset( &sigset );
   sigaddset( &sigset, SIGINT );
   sigaddset( &sigset, SIGTERM );
   sigaddset( &sigset, SIGQUIT );
   sigaddset( &sigset, SIGHUP );
   pthread_sigmask( SIG_BLOCK, &sigset, NULL );

   MYSQL *conn;
   conn = mysql_init( NULL );
   if ( ! mysql_real_connect( conn, server, prefs.mysql_user, prefs.mysql_pass, prefs.mysql_db, 0, prefs.mysql_sock, 0 ) ) { /* error */ }
   mysql_close( conn );

   // Do stuff
   ...
   pthread_exit( ( void * ) t );
}

1
投票

我想我可以回答我自己的问题,我发现我的pthread清理处理程序没有被执行(与pthread_cleanup_push一起安装)并且使用pthread_exit的代码的结束被调用的时间早于main可以取消该线程。我做了一个pthread_cleanup_pop(0)并将其更改为pthread_cleanup_pop(1),因此当线程退出的时间早于main可以取消时,清理处理程序也会被执行。在这个清理处理程序中,现在mysql_thread_end实际上有机会运行并修复了问题。


0
投票

另外:显然,MySQL客户端库并不是设计为跨线程使用连接句柄(MYSQL*)。

不要将MYSQL*从一个线程传递到另一个线程。

不要将std::async或类似功能与MySQL功能结合使用。 (代码可能会也可能不会在单独的线程中执行。)

© www.soinside.com 2019 - 2024. All rights reserved.