BEA Logo BEA Tuxedo Release 7.1

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

 

   Tuxedo Doc Home   |   Programming   |   Topic List   |   Previous   |   Next   |   Contents

   Programming a BEA Tuxedo Application Using C

Writing a Multithreaded Client

Coding Rules for a Multithreaded Client

Keep in mind the following rules for coding multithreaded clients:

Initializing a Client to Multiple Contexts

To have a client join more than one context, issue a call to the tpinit() function with the TPMULTICONTEXTS flag set in the flags element of the TPINIT data structure.

In any one process, either all calls to tpinit() must include the TPMULTICONTEXTS flag or no call to tpinit() may include this flag. The only exception to this rule is that if all of a client's application associations are terminated by successful calls to tpterm(), then the process is restored to a state in which the inclusion of the TPMULTICONTEXTS flag in the next call to tpinit() is optional.

When tpinit() is invoked with the TPMULTICONTEXTS flag set, a new application association is created and is designated the current association. The BEA Tuxedo domain to which the new association is made is determined by the value of the TUXCONFIG or WSENVFILE/WSNADDR environment variable.

When a client thread successfully executes tpinit() without the TPMULTICONTEXTS flag, all threads in the client are placed in the single-context state (TPSINGLECONTEXT).

On failure, tpinit() leaves the calling thread in its original context (that is, in the context state in which it was operating before the call to tpinit()).

Do not call tpterm() from a given context if any of the threads in that context are still working. See the table labeled Multicontext State Transitions for a description of the context states that result from calling tpterm() under these and other circumstances.

Context State Changes for a Client Thread

In a multicontext application, calls to various functions result in context state changes for the calling thread and any other threads that are active in the same context as the calling process. The following diagram illustrates the context state changes that result from calls to tpinit(), tpsetctxt(3c), and tpterm(). (The tpgetctxt(3c) function does not produce any context state changes.)

Multicontext State Transitions

Note: When tpterm() is called by a thread running in the multicontext state (TPMULTICONTEXTS), the calling thread is placed in the null context state (TPNULLCONTEXT). All other threads associated with the terminated context are switched to the invalid context state (TPINVALIDCONTEXT).

The following table lists all possible context state changes produced by calling tpinit(), tpsetctxt(3c), and tpterm().

Context State Changes for a Client Thread

When this function is executed . . .

Then a thread in this context state results in . . .

Null Context

Single Context

Multicontext

Invalid Context

tpinit() without TPMULTICONTEXTS

Single context

Single context

Error

Error

tpinit() with TPMULTICONTEXTS

Multicontext

Error

Multicontext

Error

tpsetctxt(3c) to TPNULLCONTEXT

Null

Error

Null

Null

tpsetctxt(3c) to context 0

Error

Single context

Error

Error

tpsetctxt(3c) to context > 0

Multicontext

Error

Multicontext

Multicontext

Implicit tpinit()

Single context

N/A

N/A

Error

tpterm() in this thread

Null

Null

Null

Null

tpterm() in a different thread of this context

N/A

Null

Invalid

N/A

Getting Replies in a Multithreaded Environment

tpgetrply() receives responses only to requests made via tpacall(). Requests made with tpcall() are separate and cannot be retrieved with tpgetrply() regardless of the multithreading or multicontexting level.

tpgetrply() operates in only one context, which is the context in which it is called. Therefore, when you call tpgetrply() with the TPGETANY flag, only handles generated in the same context are considered. Similarly, a handle generated in one context may not be used in another context, but the handle may be used in any thread operating within the same context.

When tpgetrply() is called in a multithreaded environment, the following restrictions apply:

Using Environment Variables in a Multithreaded and/or Multicontexted Environment

When a BEA Tuxedo application is run in an environment that is multicontexted and/or multithreaded, the following considerations apply to the use of environment variables:

Using Per-context Functions and Data Structures in a Multithreaded Client

The following ATMI functions affect only the application contexts in which they are called:

Using Per-process Functions and Data Structures in a Multithreaded Client

The following BEA Tuxedo functions affect the entire process in which they are called.

The determination of single-context mode, multicontext mode, or uninitialized mode affects an entire process. The buffer type switch, the view cache, and environment variable values are also per-process functions.

Using Per-thread Functions and Data Structures in a Multithreaded Client

Only the calling thread is affected by the following:

The Ferror, Ferror32(5), tperrno(5), tpurcode(5), and Uunix_err variables are specific to each thread.

The identity of the current context is specific to each thread.

Sample Code for a Multithreaded Client

The following example shows a multithreaded client using ATMI calls. Threads functions differ from one operating system to another. In this example, POSIX functions are used.

Note: In order to simplify this example, error checking code has not been included.

Sample Code for a Multithreaded Client


#include <stdio.h>
#include <pthread.h>
#include <atmi.h>

TPINIT * tpinitbuf;
int timeout=60;
pthread_t withdrawalthreadid, stockthreadid;
TPCONTEXT_T ctxt;
void * stackthread(void *);
void * withdrawalthread(void *);

main()
{
tpinitbuf = tpalloc(TPINIT, NULL, TPINITNEED(0));
/*
* This code will perform a transfer, using separate threads for the
* withdrawal and deposit. It will also get the current
* price of BEA stock from a separate application, and calculate how
* many shares the transferred amount can buy.
*/

tpinitbuf->flags = TPMULTICONTEXTS;

/* Fill in the rest of tpinitbuf. */
tpinit(tpinitbuf);

tpgetctxt(&ctxt, 0);
tpbegin(timeout, 0);
pthread_create(&withdrawalthreadid, NULL, withdrawalthread, NULL);
tpcall("DEPOSIT", ...);

/* Wait for the withdrawal thread to complete. */
pthread_join(withdrawalthreadid, NULL);

tpcommit(0);
tpterm();

/* Wait for the stock thread to complete. */
pthread_join(stockthreadid, NULL);

/* Print the results. */
printf("$%9.2f has been transferred \
from your savings account to your checking account.\n", ...);

printf("At the current BEA stock price of $%8.3f, \
you could purchase %d shares.\n", ...);

exit(0);
}



void *
stockthread(void *arg)
{

/* The other threads have now called tpinit(), so resetting TUXCONFIG can
* no longer adversely affect them.
*/

tuxputenv("TUXCONFIG=/home/users/xyz/stockconf");
tpinitbuf->flags = TPMULTICONTEXTS;
/* Fill in the rest of tpinitbuf. */
tpinit(tpinitbuf);
tpcall("GETSTOCKPRICE", ...);
/* Save the stock price in a variable that can also be accessed in main(). */
tpterm();
return(NULL);
}



void *
withdrawalthread(void *arg)
{
/* Create a separate thread to get stock prices from a different
* application.
*/



pthread_create(&stockthreadid, NULL, stockthread, NULL);
tpsetctxt(ctxt, 0);
tpcall("WITHDRAWAL", ...);
return(NULL);
}


See Also