Bug #12105 | Thread-safe client crushes under Windows platform. | ||
---|---|---|---|
Submitted: | 22 Jul 2005 8:03 | Modified: | 28 Jul 2005 9:23 |
Reporter: | [ name withheld ] | Email Updates: | |
Status: | Not a Bug | Impact on me: | |
Category: | MySQL Server | Severity: | S1 (Critical) |
Version: | 4.1.12 | OS: | Windows (Windows) |
Assigned to: | CPU Architecture: | Any |
[22 Jul 2005 8:03]
[ name withheld ]
[22 Jul 2005 9:09]
Aleksey Kishkin
Can you provide here an exampe? It's hard to reproduce if we dont know how exactly you tried to use mysql API in multithread application. Did you use mysql_thread_init(), mysql_thread_end()?
[22 Jul 2005 12:47]
MySQL Verification Team
Are you followed the instructions mentioned at: http://dev.mysql.com/doc/mysql/en/threaded-clients.html
[22 Jul 2005 14:49]
[ name withheld ]
// // 1. MySQL server and this client are one the same computer. // 2. If N_THREADS = 1 then everything is ok // If N_THREADS > 1 there is access violation // #include <windows.h> #include <process.h> #include <mysql.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h> #include <ctype.h> #define N_THREADS 2 #define TEST_DB_NAME "test_db" #define NUMBER_OF_ITEMS 100 typedef struct { MYSQL *pMysql; HANDLE hEventExit; } data_t; char *g_szTable = "CREATE TABLE test_tab \ ( \ col1 INT UNSIGNED NOT NULL PRIMARY KEY, \ col2 INT UNSIGNED NOT NULL, \ col3 INT UNSIGNED NOT NULL, \ col4 INT UNSIGNED NOT NULL \ )"; void show_help( char *szExe ); void press_key( char key, char *sz ); unsigned int __stdcall thread( void *pParameter ); void main( int argc, char **argv ) { int i, err; unsigned n; char szQuery[1024]; MYSQL *pMysql = NULL; char *pszExe = NULL; char *pszPassword = NULL; char *pszUser = NULL; char *pszMysqlIpAddr = NULL; unsigned short mysqlPort = 0; HANDLE hThread[N_THREADS] = {0}; data_t data = {0}; err = 1; srand( (unsigned int) time(NULL) ); switch ( argc ) { case 5: pszPassword = argv[4]; case 4: pszUser = argv[3]; case 3: mysqlPort = atoi( argv[2] ); case 2: pszMysqlIpAddr = argv[1]; } pszExe = strrchr( argv[0], '\\' ); pszExe++; do { // // init MySQL // pMysql = mysql_init( NULL ); if ( !pMysql ) { printf( "mysql_init() - ERROR\n" ); break; } // // connect to MySQL server // if ( !mysql_real_connect( pMysql, pszMysqlIpAddr, pszUser, pszPassword, NULL, mysqlPort, NULL, 0 ) ) { printf( "mysql_real_connect() - ERROR: %s\n", mysql_error( pMysql ) ); break; } // // delete old database if it exists // sprintf( szQuery, "DROP DATABASE IF EXISTS %s", TEST_DB_NAME ); if ( mysql_query( pMysql, szQuery ) ) { printf( "mysql_query( DROP DATABASE ) - ERROR: %s\n", mysql_error( pMysql ) ); } // // create new database // sprintf( szQuery, "CREATE DATABASE %s", TEST_DB_NAME ); if ( mysql_query( pMysql, szQuery ) ) { printf( "mysql_query( CREATE DATABASE ) - ERROR: %s\n", mysql_error( pMysql ) ); break; } // // select new database // if ( mysql_select_db( pMysql, TEST_DB_NAME ) ) { printf( "mysql_select_db() - ERROR: %s\n", mysql_error( pMysql ) ); break; } // // create table in new database // if ( mysql_query( pMysql, g_szTable ) ) { printf( "mysql_query( g_szTable ) - ERROR: %s\n", mysql_error( pMysql ) ); break; } // // fill database // for ( i=0; i<NUMBER_OF_ITEMS; i++ ) { // // test_tab table: // col1 INT UNSIGNED NOT NULL PRIMARY KEY // col2 INT UNSIGNED NOT NULL // col3 INT UNSIGNED NOT NULL // col4 INT UNSIGNED NOT NULL // sprintf( szQuery, "INSERT INTO test_tab VALUES( %u, %u, %u, %u )", i, i*2, i*3, i*4 ); if ( mysql_query( pMysql, szQuery ) ) { printf( "test_tab: mysql_query( szQuery_%i ) - ERROR: %s\n", i, mysql_error( pMysql ) ); break; } } if ( i == NUMBER_OF_ITEMS ) { printf( "Database '%s' was successfuly created.\n", TEST_DB_NAME ); if ( mysql_thread_safe() ) { printf( "Client is thread-safe.\n" ); } else { printf( "Client is not thread-safe.\n" ); } printf( "Start update database...\n" ); data.pMysql = pMysql; data.hEventExit = CreateEvent( NULL, TRUE, FALSE, NULL ); if ( !data.hEventExit ) break; for ( i=0; i<N_THREADS; i++ ) { hThread[i] = (HANDLE) _beginthreadex( 0, 0, thread, &data, 0, &n ); } err = 0; } } while (0); if ( err ) { show_help( pszExe ); } press_key( 'q', "to quit..." ); if ( data.hEventExit ) { SetEvent( data.hEventExit ); } for ( i=0; i<N_THREADS; i++ ) { if ( hThread[i] ) { WaitForSingleObject( hThread[i], 10000 ); CloseHandle( hThread[i] ); hThread[i] = NULL; } } if ( data.hEventExit ) { CloseHandle( data.hEventExit ); data.hEventExit = NULL; } if ( pMysql ) { mysql_close( pMysql ); pMysql = NULL; } } //********************************************************* unsigned int __stdcall thread( void *pParameter ) { int i; char szQuery[1024]; data_t *pData = (data_t *) pParameter; DWORD id = GetCurrentThreadId(); printf( "thread id=%u started\n", id ); if ( mysql_thread_init() ) { printf( "thread id=%u: mysql_thread_init() - ERROR\n", id ); } i = 0; while ( WaitForSingleObject( pData->hEventExit, 20 ) != WAIT_OBJECT_0 ) { sprintf( szQuery, "UPDATE test_tab SET col2 = %u, col3 = %u, col4 = %u WHERE col1 = %u", i*4, i*3, i*2, i ); if ( mysql_query( pData->pMysql, szQuery ) ) { printf( "thread id=%u mysql_query(%u) - ERROR: %s\n", id, i, mysql_error( pData->pMysql ) ); } i++; if ( i == NUMBER_OF_ITEMS ) i = 0; } mysql_thread_end(); printf( "thread id=%u finished\n", id ); return 0; } //********************************************************* void show_help( char *szExe ) { printf( "How to use:\n" ); printf( ">%s [mysql_ip_addr] [mysql_port] [user] [password]\n", szExe ); printf( " mysql_ip_addr - ip address of mysql server\n" ); printf( " mysql_port - port of mysql server\n" ); printf( " user - user name to connect to mysql server\n" ); printf( " password - password to connect to mysql server\n" ); printf( "\n" ); } //********************************************************* void press_key( char key, char *sz ) { if ( sz ) printf( "\nPress '%c' key %s\n", key, sz ); else printf( "\nTo continue press '%c' key...\n",key ); while ( toupper(_getch()) != toupper((int) key) ); }
[23 Jul 2005 7:30]
Vasily Kishkin
I tested the test case on Windows 2003 and got error message: Database 'test_db' was successfuly created. Client is thread-safe. Start update database... Press 'q' key to quit... thread id=3168 started thread id=3172 started thread id=3168 mysql_query(0) - ERROR: Lost connection to MySQL server during query
[23 Jul 2005 12:12]
[ name withheld ]
I have the same results but on Windows XP Professional (SP2). After this error client application crushed because of access violation in "ntdll.dll" file. >I tested the test case on Windows 2003 and got error message: >Database 'test_db' was successfuly created. >Client is thread-safe. >Start update database... >Press 'q' key to quit... >thread id=3168 started >thread id=3172 started >thread id=3168 mysql_query(0) - ERROR: Lost connection to MySQL server >during query
[28 Jul 2005 9:23]
Aleksey Kishkin
Well. functions of mysql api _are_ thread-safe, but if you want to share _one_ connection in the all threads, you must lock mysql_query and mysql_store_results by mutex (or any similar things). If you open connection for each thread, you don't need to lock any section of code. It's in the documentation that Miguel mentioned. (http://dev.mysql.com/doc/mysql/en/threaded-clients.html).
[28 Jul 2005 9:38]
[ name withheld ]
Thank you. I was not careful with documentation. Now I see that mysqlclient.lib is thread-safe only per connection for each thread. Several threads can't share the same connection simultaneously without of synchronization objects.