![]() |
![]() |
|
|
Writing a Multithreaded Client
Note: The BEA Tuxedo system does not support multithreaded COBOL applications.
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().
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:
The same behavior occurs if a thread calls tpgetrply() with the TPGETANY flag while another thread in the same context is already waiting in tpgetrply() for a specific handle. These restrictions protect a thread that is waiting on a specific handle from having its reply taken by a thread waiting on any handle.
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:
Note: The environment is initially empty for those operating systems that do not recognize an operating system environment.
Caching is done on a . . . For environment variables such as . . .
Per-context basis
TUXCONFIG
FIELDTBLS and FIELDTBLS32
FLDTBLDIR and FLDTBLDIR32
ULOGPFX
VIEWDIR and VIEWDIR32
VIEWFILES and VIEWFILES32
WSNADDR
WSDEVICE
WSENV
Per-process basis
TMTRACE
TUXDIR
ULOGDEBUG
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:
Note: For tpbroadcast(), the broadcast message is identified as having come from a particular application association. For tpnotify(3c), the notification is identified as having come from a particular application association. See "Using Per-process Functions and Data Structures in a Multithreaded Client" for notes about tpinit(). If tpsetunsol() is called from a thread that is not associated with a context, a per-process default unsolicited message handler for all new tpinit() contexts created is established. A specific context may change the unsolicited message handler for that context by calling tpsetunsol() again when the context is active. The per-process default unsolicited message handler may be changed by again calling tpsetunsol() in a thread not currently associated with a context.
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
![]() |
![]() |
![]() |
|
Copyright © 2000 BEA Systems, Inc. All rights reserved.
|