我使用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个线程没有退出
........
答案 0 :(得分: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 :(得分:1)
我想我可以回答我自己的问题,我发现我的pthread清理处理程序没有被执行(与pthread_cleanup_push一起安装)并且pthread_exit的代码结束被调用的时间比main可以取消线程更快。我做了一个pthread_cleanup_pop(0)并将其更改为pthread_cleanup_pop(1),因此当线程退出的时间早于main可以取消时,清理处理程序也会被执行。在这个清理处理程序中,现在mysql_thread_end实际上有机会运行并修复了问题。
答案 2 :(得分:0)
添加:显然,MySQL客户端库并非旨在跨线程使用连接句柄(MYSQL*
)。
请勿将MYSQL*
从一个线程传递到另一个线程。
请勿将std::async
或类似功能与MySQL函数结合使用。 (代码可能会或可能不会在单独的线程中执行。)