From 81859cf3cad74a7d8cc5938255ac8daa1cf15514 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Thu, 2 Sep 2010 21:48:14 +0200 Subject: added a threading test 9, but not working yet --- tests/GNUmakefile | 2 +- tests/test9.MUST | 1 + tests/test9.cpp | 104 ++++++++++++++++++++++++++++++++++++++--- tests/threads.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/threads.h | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 358 insertions(+), 8 deletions(-) create mode 100644 tests/threads.c create mode 100644 tests/threads.h diff --git a/tests/GNUmakefile b/tests/GNUmakefile index c84d19b..87122a1 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -24,7 +24,7 @@ TEST_CPP_BINS = \ test6$(EXE) \ test7$(EXE) \ test8$(EXE) \ - test9$(EXE) + threads.o test9$(EXE) TEST_BINS = \ testc$(EXE) diff --git a/tests/test9.MUST b/tests/test9.MUST index f4f0227..985eccc 100644 --- a/tests/test9.MUST +++ b/tests/test9.MUST @@ -1,2 +1,3 @@ creating DB.. connection object is sqlite3xx::connection(test9.db) +create table.. diff --git a/tests/test9.cpp b/tests/test9.cpp index af4a035..5b57a87 100644 --- a/tests/test9.cpp +++ b/tests/test9.cpp @@ -27,10 +27,80 @@ #if !defined _WIN32 #include #endif /* !defined _WIN32 */ +#include "threads.h" using namespace sqlite3xx; using namespace std; +const int NOF_PRODUCERS = 2; +const int NOF_CONSUMERS = 2; +const int NOF_PRODUCER_TRANSACTIONS = 10; +const int NOF_PRODUCER_OPS = 10; +const int NOF_CONSUMER_TRANSACTIONS = 10; +const int NOF_CONSUMER_OPS = 10; + +#define UNUSED( x ) if( 0 && (x) ) { } + +MUTEX_TYPE cout_mutex; + +static THREAD_FUNC_DECL produce( void *thread_data ) +{ + UNUSED( thread_data ); + + try { + connection c( "test9.db" ); + c.prepare( "ins", "insert into x values( ? )" )( "text", sqlite3xx::prepare::treat_direct ); + + for( int i = 0; i < NOF_PRODUCER_TRANSACTIONS; i++ ) { + work t( c, "ins" ); + MUTEX_LOCK( cout_mutex ); + cout << "producer transaction " << i << " started" << endl; + MUTEX_UNLOCK( cout_mutex ); + for( int j = 0; j < NOF_PRODUCER_OPS; j++ ) { + result r = t.prepared( "ins" )( i * 1000 + j ).exec( ); + assert( r.affected_rows( ) == 1 ); + } + t.commit( ); + } + } catch( sql_error& e ) { + cerr << "producer error, " << e.msg( ) << ": " << e.query( ) << endl; + } + + THREAD_FUNC_RETURN; +} + +static THREAD_FUNC_DECL consume( void *thread_data ) +{ + UNUSED( thread_data ); + + try { + connection c( "test9.db" ); + c.prepare( "sel", "select * from x" ); + + for( int i = 0; i < NOF_CONSUMER_TRANSACTIONS; i++ ) { + work t( c, "sel" ); + MUTEX_LOCK( cout_mutex ); + cout << "consumer transaction " << i << " started" << endl; + MUTEX_UNLOCK( cout_mutex ); + for( int j = 0; j < NOF_CONSUMER_OPS; j++ ) { + result r = t.prepared( "sel" ).exec( ); + for( result::const_iterator it = r.begin( ); it < r.end( ); it++ ) { + int x; + it["x"].to( x ); + } + MUTEX_LOCK( cout_mutex ); + cout << "consumer transaction got " << r.size( ) << " rows." << endl; + MUTEX_UNLOCK( cout_mutex ); + } + t.commit( ); + } + } catch( sql_error& e ) { + cerr << "consumer error, " << e.msg( ) << ": " << e.query( ) << endl; + } + + THREAD_FUNC_RETURN; +} + int main( ) { (void)unlink( "test9.db" ); @@ -39,7 +109,34 @@ int main( ) { connection c( "test9.db" ); cout << "connection object is " << c << endl; + cout << "create table.." << endl; c.exec( "create table x( x integer )" ); + + // now have some threads creating data and some others + // consuming it. stupid, but should nicely stress the thing + THREAD_TYPE prod[NOF_PRODUCERS]; + THREAD_TYPE cons[NOF_CONSUMERS]; + + MUTEX_SETUP( cout_mutex ); + + for( int i = 0; i < NOF_PRODUCERS; i++ ) { + THREAD_CREATE( &prod[i], produce, NULL ); + } + + for( int i = 0; i < NOF_CONSUMERS; i++ ) { + THREAD_CREATE( &cons[i], consume, NULL ); + } + + for( int i = 0; i < NOF_PRODUCERS; i++ ) { + THREAD_JOIN( prod[i] ); + } + + for( int i = 0; i < NOF_CONSUMERS; i++ ) { + THREAD_JOIN( cons[i] ); + } + + MUTEX_CLEANUP( cout_mutex ); + } catch( sql_error& e ) { cerr << e.msg( ) << ": " << e.query( ) << endl; } @@ -48,13 +145,6 @@ int main( ) { /* try { - cout << "starting transaction.." << endl; - work wc( c, "create" ); - - cout << "create table.." << endl; - wc.exec( "create table a( i integer, d double, s text, t text )" ); - wc.commit( ); - work wi( c, "insert" ); cout << "insert some data.." << endl; c.prepare( "ins", "insert into a( i, d, s, t ) values( NULL, NULL, NULL, ? )" ) diff --git a/tests/threads.c b/tests/threads.c new file mode 100644 index 0000000..98195de --- /dev/null +++ b/tests/threads.c @@ -0,0 +1,122 @@ +/* + threads.c + + Posix and Windows threads + +gSOAP XML Web services tools +Copyright (C) 2000-2009, Robert van Engelen, Genivia Inc., All Rights Reserved. +This part of the software is released under one of the following licenses: +GPL, the gSOAP public license, or Genivia's license for commercial use. +-------------------------------------------------------------------------------- +gSOAP public license. + +The contents of this file are subject to the gSOAP Public License Version 1.3 +(the "License"); you may not use this file except in compliance with the +License. You may obtain a copy of the License at +http://www.cs.fsu.edu/~engelen/soaplicense.html +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the License. + +The Initial Developer of the Original Code is Robert A. van Engelen. +Copyright (C) 2000-2009, Robert van Engelen, Genivia Inc., All Rights Reserved. +-------------------------------------------------------------------------------- +GPL license. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +Author contact information: +engelen@genivia.com / engelen@acm.org + +This program is released under the GPL with the additional exemption that +compiling, linking, and/or using OpenSSL is allowed. +-------------------------------------------------------------------------------- +A commercial use license is available from Genivia, Inc., contact@genivia.com +-------------------------------------------------------------------------------- +*/ + +#include "threads.h" + +/******************************************************************************\ + * + * Emulation of POSIX condition variables for WIN32 + * +\******************************************************************************/ + +#ifdef WIN32 + +#ifdef __cplusplus +extern "C" { +#endif + +int emulate_pthread_cond_init(COND_TYPE *cv) +{ + cv->waiters_count_ = 0; + cv->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); + InitializeCriticalSection(&cv->waiters_count_lock_); + + return 0; +} + +int emulate_pthread_cond_destroy(COND_TYPE *cv) +{ + CloseHandle(cv->signal_event_); + DeleteCriticalSection(&cv->waiters_count_lock_); + + return 0; +} + +int emulate_pthread_cond_signal(COND_TYPE *cv) +{ + int have_waiters; + + EnterCriticalSection(&cv->waiters_count_lock_); + have_waiters = cv->waiters_count_ > 0; + LeaveCriticalSection(&cv->waiters_count_lock_); + + if (have_waiters) + return SetEvent(cv->signal_event_) == 0; + + return 0; +} + +int emulate_pthread_cond_wait(COND_TYPE *cv, MUTEX_TYPE *cs) +{ + int result; + + EnterCriticalSection(&cv->waiters_count_lock_); + cv->waiters_count_++; + LeaveCriticalSection(&cv->waiters_count_lock_); + + ReleaseMutex(*cs); + + result = (WaitForSingleObject(cv->signal_event_, INFINITE) == WAIT_FAILED); + + if (!result) + { + EnterCriticalSection(&cv->waiters_count_lock_); + cv->waiters_count_--; + LeaveCriticalSection(&cv->waiters_count_lock_); + + result = (WaitForSingleObject(*cs, INFINITE) == WAIT_FAILED); + } + + return result; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/threads.h b/tests/threads.h new file mode 100644 index 0000000..dec8ddc --- /dev/null +++ b/tests/threads.h @@ -0,0 +1,137 @@ +/* + threads.h + + Posix and Windows threads interface + +gSOAP XML Web services tools +Copyright (C) 2000-2005, Robert van Engelen, Genivia Inc., All Rights Reserved. +This part of the software is released under one of the following licenses: +GPL, the gSOAP public license, or Genivia's license for commercial use. +-------------------------------------------------------------------------------- +gSOAP public license. + +The contents of this file are subject to the gSOAP Public License Version 1.3 +(the "License"); you may not use this file except in compliance with the +License. You may obtain a copy of the License at +http://www.cs.fsu.edu/~engelen/soaplicense.html +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the License. + +The Initial Developer of the Original Code is Robert A. van Engelen. +Copyright (C) 2000-2005, Robert van Engelen, Genivia Inc., All Rights Reserved. +-------------------------------------------------------------------------------- +GPL license. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +Author contact information: +engelen@genivia.com / engelen@acm.org + +This program is released under the GPL with the additional exemption that +compiling, linking, and/or using OpenSSL is allowed. +-------------------------------------------------------------------------------- +A commercial use license is available from Genivia, Inc., contact@genivia.com +-------------------------------------------------------------------------------- +*/ + +#ifndef THREADS_H +#define THREADS_H + +#ifndef _WIN32 +# include /* defines _POSIX_THREADS if pthreads are available */ +#else +# define ssize_t int +# include +# include +# include +# include +#endif + +#if defined(_POSIX_THREADS) || defined(_SC_THREADS) +# include +#endif + +/******************************************************************************\ + * + * Threads + * +\******************************************************************************/ + +#if defined(_WIN32) +# define SLEEP(x) Sleep((x) * 1000) +# define THREAD_TYPE HANDLE +# define THREAD_FUNC_DECL unsigned int _stdcall +# define THREAD_FUNC_RETURN return 0; +# define THREAD_ID GetCurrentThreadId() +# define THREAD_CREATE(x,y,z) *(x) = (HANDLE)_beginthreadex( NULL, 8*4096, (y), (z), 0, NULL) +# define THREAD_DETACH(x) +# define THREAD_JOIN(x) WaitForSingleObject((x), INFINITE) +# define THREAD_EXIT _endthread() +# define MUTEX_TYPE HANDLE +# define MUTEX_INITIALIZER CreateMutex(NULL, FALSE, NULL) +# define MUTEX_SETUP(x) (x) = CreateMutex(NULL, FALSE, NULL) +# define MUTEX_CLEANUP(x) CloseHandle(x) +# define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE) +# define MUTEX_UNLOCK(x) ReleaseMutex(x) +# define COND_SETUP(x) emulate_pthread_cond_init(&(x)) +# define COND_CLEANUP(x) emulate_pthread_cond_destroy(&(x)) +# define COND_SIGNAL(x) emulate_pthread_cond_signal(&(x)) +# define COND_WAIT(x,y) emulate_pthread_cond_wait(&(x), &(y)) +typedef struct +{ u_int waiters_count_; + CRITICAL_SECTION waiters_count_lock_; + HANDLE signal_event_; +} COND_TYPE; +#ifdef __cplusplus +extern "C" { +#endif +int emulate_pthread_cond_init(COND_TYPE*); +int emulate_pthread_cond_destroy(COND_TYPE*); +int emulate_pthread_cond_signal(COND_TYPE*); +int emulate_pthread_cond_wait(COND_TYPE*, MUTEX_TYPE*); +#ifdef __cplusplus +} +#endif +#elif defined(_POSIX_THREADS) || defined(_SC_THREADS) +# define SLEEP(x) sleep(x) +# define THREAD_TYPE pthread_t +# define THREAD_FUNC_DECL void * +# define THREAD_FUNC_RETURN return NULL; +# define THREAD_ID pthread_self() +# define THREAD_CREATE(x,y,z) pthread_create((x), NULL, (y), (z)) +# define THREAD_DETACH(x) pthread_detach((x)) +# define THREAD_JOIN(x) pthread_join((x), NULL) +# define THREAD_EXIT pthread_exit(NULL) +# define MUTEX_TYPE pthread_mutex_t +# define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +# define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL) +# define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x)) +#if 0 /* 1: DEBUG MUTEX */ +# define MUTEX_LOCK(x) (fprintf(stderr, "! LOCK %p %s:%d\n", &x, __FILE__, __LINE__), pthread_mutex_lock(&(x))) +# define MUTEX_UNLOCK(x) (fprintf(stderr, "! UNLOCK %p %s:%d\n", &x, __FILE__, __LINE__), pthread_mutex_unlock(&(x))) +#else +# define MUTEX_LOCK(x) pthread_mutex_lock(&(x)) +# define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x)) +#endif +# define COND_TYPE pthread_cond_t +# define COND_SETUP(x) pthread_cond_init(&(x), NULL) +# define COND_CLEANUP(x) pthread_cond_destroy(&(x)) +# define COND_SIGNAL(x) pthread_cond_signal(&(x)) +# define COND_WAIT(x,y) pthread_cond_wait(&(x), &(y)) +#else +# error "No POSIX threads detected: we need thread and mutex operations. See for example OpenSSL /threads/th-lock.c on how to implement mutex on your platform" +#endif + +#endif -- cgit v1.2.3-54-g00ecf