Re: Looking for ESQL/C Multithreaded Source Code Example
Posted in 2010
Topics: SQL Development & Query Writing, Stored Procedures & SPL, Error Codes & Troubleshooting, Connectivity: ESQL/C, 4GL & Embedded SQL, Platform-Specific Issues, Versions, Editions & End-of-Life
On Feb 13, 1:08 pm, the_omega...@yahoo.com wrote: > I am looking for an example of functional ESQL/C source code that > demonstrates multi-threading. I have found the thread_safe example > in the ESQL/C programmers guide, but I have not had any luck getting > it to compile. I did not find an example in $INFORMIXDIR/demo/esqlc > or anywhere on the net. > I am running IDS 10.00 and 11.50 on Solaris 10 with CSDK 3.50. Hmm...yes, I can see why that example is hard to compile these days. I don't know which systems have DCE threads as opposed to POSIX pthreads. I've taken the code from the example (p13-20 to p13-25 in the ESQL/C 3.50 Manual c2394200.pdf) and extracted it into the code below. I have to regard it as, at best, 'unpretty'... /* ************************************************************** * Program Name: thread_safe() * * purpose: If a server connection is initiated with the WITH * CONCURRENT TRANSACTION clause, an ongoing transaction can be * shared across threads that subsequently connect to that server. * In addition, if an open cursor is associated with such connection, * the cursor will remain open when the connection is made dormant. * Therefore, multiple threads can share a cursor. * * Methods : - Create database db_con221 and table t1. * - Insert 6 rows into table t1, i.e. values 1 through 6. * - Connect to db_con221 as con1 with CONCURRENT TRANSACTION. * The CONCURRENT TRANSACTION option is required since all threads * use the cursor throughout the same connection. * - Declare c1 cursor for "select a from t1 order by a". * - Open the cursor. * - Start 6 threads. Use DCE pthread_join() to determine if * all threads complete & all threads do same thing as * follows. * For thread_1, thread_2, ..., thread_6: * o SET CONNECTION con1 * o FETCH a record and display it. * o SET CONNECTION con1 DORMANT * - Disconnect all connections. ************************************************************** */ #include <pthread.h> #include <dce/dce_error.h> /* global definitions */ #define num_threads 6 /* Function definitions */ static void thread_all(); static long dr_dbs(); static int checksql(char *str, long expected_err, char *con_name); static void dce_err(); /* Host variables declaration */ EXEC SQL BEGIN DECLARE SECTION; char con1[] = "con1"; EXEC SQL END DECLARE SECTION; /* **************************************************** * Main Thread ******************************************************/ main() { /* create database */ EXEC SQL CREATE DATABASE db_con221 WITH LOG; if (!checksql("create database", 0, EMPTYSTR)) { printf("MAIN:: create database returned status {%d}\\n", SQLCODE); exit(1); } EXEC SQL CREATE TABLE t1( sales INT); if (!checksql( "create_table", 0, EMPTYSTR)) { dr_dbs("db_con221"); printf("MAIN:: create table returned status {%d}\\n", SQLCODE); exit(1); } if (populate_tab() != FUNCSUCC) { dr_dbs("db_con221"); printf("MAIN:: returned status {%d}\\n", SQLCODE); exit(1); } EXEC SQL CLOSE DATABASE; checksql("[main] <close database>", 0, EMPTYSTR); /* Establish connection ’con1’ */ EXEC SQL CONNECT TO ’db_con221’ AS ’con1’ WITH CONCURRENT TRANSACTION; if (! checksql("MAIN:: <close database>", 0, EMPTYSTR)) { dr_dbs("db_con221"); exit(1); } /* Declare cursor c1 associated with the connection con1 */ EXEC SQL PREPARE tabid FROM "select sales from t1 order by sales"; checksql("MAIN:: <prepare>", 0, EMPTYSTR); EXEC SQL DECLARE c1 CURSOR FOR tabid; checksql("MAIN:: <declare c1 cursor for>", 0, EMPTYSTR); /* Open cursor c1 and make the connection dormant */ EXEC SQL OPEN c1; checksql("MAIN:: <open c1>", 0, EMPTYSTR); EXEC SQL SET CONNECTION :con1 DORMANT; checksql("MAIN:: <set connection con1 dormant>", 0, EMPTYSTR); /* Start threads */ start_threads(); /* Close cursor and drop database */ EXEC SQL SET CONNECTION :con1; checksql("MAIN:: set connection", 0, EMPTYSTR); EXEC SQL CLOSE c1; checksql("MAIN:: <close cursor>", 0, EMPTYSTR); EXEC SQL free c1; checksql("MAIN:: <free cursor>", 0, EMPTYSTR); EXEC SQL DISCONNECT ALL; checksql("MAIN:: disconnect all", 0, EMPTYSTR); dr_dbs("db_con221"); } /* end of Main Thread */ / ********************************************************************** * Function: thread_all() * Purpose : Uses connection con1 and fetches a row from table t1 using * cursor c1. * Returns : Nothing **********************************************************************/ static void thread_all(thread_num) int *thread_num; { EXEC SQL BEGIN DECLARE SECTION; int val; EXEC SQL END DECLARE SECTION; /* Wait for the connection to become available */ do { EXEC SQL SET CONNECTION :con1; } while (SQLCODE == -1802); checksql("thread_all: set connection", 0, con1); /* Fetch a row */ EXEC SQL FETCH c1 INTO :val; checksql("thread_all: fetch c1 into :val", 0, con1); /* Free connection con1 */ EXEC SQL SET CONNECTION :con1 DORMANT; checksql("thread_all: set connection con1 dormant", 0, EMPTYSTR); printf("Thread id %d fetched value %d from t1\\n", *thread_num, val); } /* thread_all() */ / ********************************************************************** * Function: start_threads() * purpose : Create num_threads and passes a thread id number to each * thread **********************************************************************/ start_threads() { int thread_num[num_threads]; pthread_t thread_id[num_threads]; int i, ret, return_value; for(i=0; i< num_threads; i++) { thread_num[i] = i; if ((pthread_create(&thread_id[i], pthread_attr_default (pthread_startroutine_t ) thread_all, &thread_num[i])) == -1) { dce_err(__FILE__, "pthread_create failed", (unsigned long)-1); dr_dbs("db_con221"); exit(1); } } /* Wait for all the threads to complete their work */ for(i=0; i< num_threads; i++) { ret = pthread_join(thread_id[i], (pthread_addr_t *) &return_value); if(ret == -1) { dce_err(__FILE__, "pthread_join", (unsigned long)-1); dr_dbs("db_con221"); exit(1); } } } /* start_threads() */ / ********************************************************************** * Function: populate_tab() * Purpose : insert values in table t1. * Returns : FUNCSUCC on success and FUNCFAIL when it fails. *******************************************************
On Feb 15, 12:42 am, Jonathan Leffler <jonathan.leff...@gmail.com> wrote: > On Feb 13, 1:08 pm, the_omega...@yahoo.com wrote: > > > I am looking for an example of functional ESQL/C source code that > > demonstrates multi-threading. I have found the thread_safe example > > in the ESQL/C programmers guide, but I have not had any luck getting > > it to compile. I did not find an example in $INFORMIXDIR/demo/esqlc > > or anywhere on the net. > > I am running IDS 10.00 and 11.50 on Solaris 10 with CSDK 3.50. > > Hmm...yes, I can see why that example is hard to compile these days. > I don't know which systems have DCE threads as opposed to POSIX > pthreads. > > I've taken the code from the example (p13-20 to p13-25 in the ESQL/C > 3.50 Manual c2394200.pdf) > and extracted it into the code below. I have to regard it as, at > best, 'unpretty'... > > /* ************************************************************** > * Program Name: thread_safe() > * > * purpose: If a server connection is initiated with the WITH > * CONCURRENT TRANSACTION clause, an ongoing transaction can be > * shared across threads that subsequently connect to that server. > * In addition, if an open cursor is associated with such connection, > * the cursor will remain open when the connection is made dormant. > * Therefore, multiple threads can share a cursor. > * > * Methods : - Create database db_con221 and table t1. > * - Insert 6 rows into table t1, i.e. values 1 through 6. > * - Connect to db_con221 as con1 with CONCURRENT TRANSACTION. > * The CONCURRENT TRANSACTION option is required since all threads > * use the cursor throughout the same connection. > * - Declare c1 cursor for "select a from t1 order by a". > * - Open the cursor. > * - Start 6 threads. Use DCE pthread_join() to determine if > * all threads complete & all threads do same thing as > * follows. > * For thread_1, thread_2, ..., thread_6: > * o SET CONNECTION con1 > * o FETCH a record and display it. > * o SET CONNECTION con1 DORMANT > * - Disconnect all connections. > ************************************************************** */ > > #include <pthread.h> > #include <dce/dce_error.h> /* global definitions */ > #define num_threads 6 > > /* Function definitions */ > static void thread_all(); > static long dr_dbs(); > static int checksql(char *str, long expected_err, char *con_name); > static void dce_err(); > /* Host variables declaration */ > EXEC SQL BEGIN DECLARE SECTION; > char con1[] = "con1"; > EXEC SQL END DECLARE SECTION; > > /* **************************************************** > * Main Thread > ******************************************************/ > > main() > { > /* create database */ > EXEC SQL CREATE DATABASE db_con221 WITH LOG; > if (!checksql("create database", 0, EMPTYSTR)) > { > printf("MAIN:: create database returned status {%d}\\n", > SQLCODE); > exit(1); > } > EXEC SQL CREATE TABLE t1( sales INT); > if (!checksql( "create_table", 0, EMPTYSTR)) > { > dr_dbs("db_con221"); > printf("MAIN:: create table returned status {%d}\\n", SQLCODE); > exit(1); > } > if (populate_tab() != FUNCSUCC) > { > dr_dbs("db_con221"); > printf("MAIN:: returned status {%d}\\n", SQLCODE); > exit(1); > } > EXEC SQL CLOSE DATABASE; > checksql("[main] <close database>", 0, EMPTYSTR); > /* Establish connection ’con1’ */ > EXEC SQL CONNECT TO ’db_con221’ AS ’con1’ WITH CONCURRENT > TRANSACTION; > if (! checksql("MAIN:: <close database>", 0, EMPTYSTR)) > { > dr_dbs("db_con221"); > exit(1); > } > /* Declare cursor c1 associated with the connection con1 */ > EXEC SQL PREPARE tabid FROM "select sales from t1 order by sales"; > checksql("MAIN:: <prepare>", 0, EMPTYSTR); > EXEC SQL DECLARE c1 CURSOR FOR tabid; > checksql("MAIN:: <declare c1 cursor for>", 0, EMPTYSTR); > /* Open cursor c1 and make the connection dormant */ > EXEC SQL OPEN c1; checksql("MAIN:: <open c1>", 0, EMPTYSTR); > EXEC SQL SET CONNECTION :con1 DORMANT; > checksql("MAIN:: <set connection con1 dormant>", 0, EMPTYSTR); > /* Start threads */ > start_threads(); > /* Close cursor and drop database */ > EXEC SQL SET CONNECTION :con1; > checksql("MAIN:: set connection", 0, EMPTYSTR); > EXEC SQL CLOSE c1; > checksql("MAIN:: <close cursor>", 0, EMPTYSTR); > EXEC SQL free c1; > checksql("MAIN:: <free cursor>", 0, EMPTYSTR); > EXEC SQL DISCONNECT ALL; > checksql("MAIN:: disconnect all", 0, EMPTYSTR); > dr_dbs("db_con221"); > > } /* end of Main Thread */ > > / > ********************************************************************** > * Function: thread_all() > * Purpose : Uses connection con1 and fetches a row from table t1 using > * cursor c1. > * Returns : Nothing > **********************************************************************/ > static void thread_all(thread_num) > int *thread_num; > { > EXEC SQL BEGIN DECLARE SECTION; > int val; > EXEC SQL END DECLARE SECTION; > /* Wait for the connection to become available */ > do { > EXEC SQL SET CONNECTION :con1; > } while (SQLCODE == -1802); > checksql("thread_all: set connection", 0, con1); > /* Fetch a row */ > EXEC SQL FETCH c1 INTO :val; > checksql("thread_all: fetch c1 into :val", 0, con1); > /* Free connection con1 */ > EXEC SQL SET CONNECTION :con1 DORMANT; > checksql("thread_all: set connection con1 dormant", 0, EMPTYSTR); > > printf("Thread id %d fetched value %d from t1\\n", *thread_num, > val); > > } /* thread_all() */ > > / > ********************************************************************** > * Function: start_threads() > * purpose : Create num_threads and passes a thread id number to each > * thread > **********************************************************************/ > start_threads() > { > int thread_num[num_threads]; > pthread_t thread_id[num_threads]; > int i, ret, return_value; > for(i=0; i< num_threads; i++) > { > thread_num[i] = i; > if ((pthread_create(&thread_id[i], pthread_attr_default > (pthread_startroutine_t ) thread_all, &thread_num[i])) == -1) > { > dce_err(__FILE__, "pthread_create failed", (unsigned > long)-1); > dr_dbs("db_con221"); > exit(1); > } > } > /* Wait for all the threads to complete their work */ > for(i=0; i< num_threads; i++) > { > ret = pthread_join(thread_id[i], (pthread_addr_t *) > &return_value); > if(ret == -1) > { > dce_err(__FILE__, @@D
Sorry to top post. I think the idea of following Djisktra 'Librarian' problem which as Art puts it, a single writer to multiple readers from a queue. Whether you use threads or fork() the process, it shouldn't really matter. Sure, threads are more efficient, but with respect to the task at hand, forking a process doesn't really matter. The point is that each consumer (reader) thread/process should have its own connection to the database. If you don't like ESQL/C, then go with Java and their threading models. > From: jonathan.leffler@gmail.com > Subject: Re: Looking for ESQL/C Multithreaded Source Code Example > Date: Sun, 14 Feb 2010 21:42:31 -0800 > To: informix-list@iiug.org > CC: docinf@us.ibm.com; jleffler@us.ibm.com > > On Feb 13, 1:08 pm, the_omega...@yahoo.com wrote: > > I am looking for an example of functional ESQL/C source code that > > demonstrates multi-threading. I have found the thread_safe example > > in the ESQL/C programmers guide, but I have not had any luck getting > > it to compile. I did not find an example in $INFORMIXDIR/demo/esqlc > > or anywhere on the net. > > > I am running IDS 10.00 and 11.50 on Solaris 10 with CSDK 3.50. > > Hmm...yes, I can see why that example is hard to compile these days. > I don't know which systems have DCE threads as opposed to POSIX > pthreads. > > I've taken the code from the example (p13-20 to p13-25 in the ESQL/C > 3.50 Manual c2394200.pdf) > and extracted it into the code below. I have to regard it as, at > best, 'unpretty'... > > /* ************************************************************** > * Program Name: thread_safe() > * > * purpose: If a server connection is initiated with the WITH > * CONCURRENT TRANSACTION clause, an ongoing transaction can be > * shared across threads that subsequently connect to that server. > * In addition, if an open cursor is associated with such connection, > * the cursor will remain open when the connection is made dormant. > * Therefore, multiple threads can share a cursor. > * > * Methods : - Create database db_con221 and table t1. > * - Insert 6 rows into table t1, i.e. values 1 through 6. > * - Connect to db_con221 as con1 with CONCURRENT TRANSACTION. > * The CONCURRENT TRANSACTION option is required since all threads > * use the cursor throughout the same connection. > * - Declare c1 cursor for "select a from t1 order by a". > * - Open the cursor. > * - Start 6 threads. Use DCE pthread_join() to determine if > * all threads complete & all threads do same thing as > * follows. > * For thread_1, thread_2, ..., thread_6: > * o SET CONNECTION con1 > * o FETCH a record and display it. > * o SET CONNECTION con1 DORMANT > * - Disconnect all connections. > ************************************************************** */ > > #include <pthread.h> > #include <dce/dce_error.h> /* global definitions */ > #define num_threads 6 > > /* Function definitions */ > static void thread_all(); > static long dr_dbs(); > static int checksql(char *str, long expected_err, char *con_name); > static void dce_err(); > /* Host variables declaration */ > EXEC SQL BEGIN DECLARE SECTION; > char con1[] = "con1"; > EXEC SQL END DECLARE SECTION; > > /* **************************************************** > * Main Thread > ******************************************************/ > > main() > { > /* create database */ > EXEC SQL CREATE DATABASE db_con221 WITH LOG; > if (!checksql("create database", 0, EMPTYSTR)) > { > printf("MAIN:: create database returned status {%d}\\n", > SQLCODE); > exit(1); > } > EXEC SQL CREATE TABLE t1( sales INT); > if (!checksql( "create_table", 0, EMPTYSTR)) > { > dr_dbs("db_con221"); > printf("MAIN:: create table returned status {%d}\\n", SQLCODE); > exit(1); > } > if (populate_tab() != FUNCSUCC) > { > dr_dbs("db_con221"); > printf("MAIN:: returned status {%d}\\n", SQLCODE); > exit(1); > } > EXEC SQL CLOSE DATABASE; > checksql("[main] <close database>", 0, EMPTYSTR); > /* Establish connection ’con1’ */ > EXEC SQL CONNECT TO ’db_con221’ AS ’con1’ WITH CONCURRENT > TRANSACTION; > if (! checksql("MAIN:: <close database>", 0, EMPTYSTR)) > { > dr_dbs("db_con221"); > exit(1); > } > /* Declare cursor c1 associated with the connection con1 */ > EXEC SQL PREPARE tabid FROM "select sales from t1 order by sales"; > checksql("MAIN:: <prepare>", 0, EMPTYSTR); > EXEC SQL DECLARE c1 CURSOR FOR tabid; > checksql("MAIN:: <declare c1 cursor for>", 0, EMPTYSTR); > /* Open cursor c1 and make the connection dormant */ > EXEC SQL OPEN c1; checksql("MAIN:: <open c1>", 0, EMPTYSTR); > EXEC SQL SET CONNECTION :con1 DORMANT; > checksql("MAIN:: <set connection con1 dormant>", 0, EMPTYSTR); > /* Start threads */ > start_threads(); > /* Close cursor and drop database */ > EXEC SQL SET CONNECTION :con1; > checksql("MAIN:: set connection", 0, EMPTYSTR); > EXEC SQL CLOSE c1; > checksql("MAIN:: <close cursor>", 0, EMPTYSTR); > EXEC SQL free c1; > checksql("MAIN:: <free cursor>", 0, EMPTYSTR); > EXEC SQL DISCONNECT ALL; > checksql("MAIN:: disconnect all", 0, EMPTYSTR); > dr_dbs("db_con221"); > } /* end of Main Thread */ > > / > ********************************************************************** > * Function: thread_all() > * Purpose : Uses connection con1 and fetches a row from table t1 using > * cursor c1. > * Returns : Nothing > **********************************************************************/ > static void thread_all(thread_num) > int *thread_num; > { > EXEC SQL BEGIN DECLARE SECTION; > int val; > EXEC SQL END DECLARE SECTION; > /* Wait for the connection to become available */ > do { > EXEC SQL SET CONNECTION :con1; > } while (SQLCODE == -1802); > checksql("thread_all: set connection", 0, con1); > /* Fetch a row */ > EXEC SQL FETCH c1 INTO :val; > checksql("thread_all: fetch c1 into :val", 0, con1); > /* Free connection con1 */ > EXEC SQL SET CONNECTION :con1 DORMANT; > checksql("thread_all: set connection con1 dormant", 0, EMPTYSTR); > > printf("Thread id %d fetched value %d from t1\\n", *thread_num, > val); > } /* thread_all() */ > > / > ********************************************************************** > * Function: start_threads() > * purpose : Create num_threads and passes a thread id number to each > * thread > **********************************************************************/ > start_threads() > { > int thread_num[num_threads]; > pthread_t thread_id[num_threads]; > int i, ret, return_value; > for(i=0; i< num_threads; i+