To find out whether your platform supports a kernel-level threads package, C functions, or POSIX functions, see the data sheet for your operating system in Installing the Oracle Tuxedo System.Many platforms have idiosyncratic requirements for multithreaded and multicontexted applications. Installing the Oracle Tuxedo System lists these platform-specific requirements. To find out what is needed on your platform, check the appropriate data sheet.The Oracle Tuxedo system allows you to use a single process to perform multiple tasks simultaneously. The programming techniques for implementing this sort of process usage are multithreading and multicontexting. This topic provides basic information about these techniques:Multithreading is the inclusion of more than one unit of execution in a single process. In a multithreaded application, multiple simultaneous calls can be made from the same process. For example, an individual process is not limited to one outstanding tpcall(3c).Figure 10‑1 shows how a multithreaded client can issue calls to three servers simultaneously.Figure 10‑1 Sample Multithreaded ProcessFigure 10‑2 shows how a server process can dispatch multiple threads to different clients simultaneously.Figure 10‑3 shows how a multicontexted client process works within a domain. Each arrow represents an outstanding call to a server.Figure 10‑3 Multicontexted Process in Two Domains
• To join multiple contexts, clients call the tpinit(3c) function with the TPMULTICONTEXTS flag set in the flags element of the TPINFO data type.When tpinit() is called with the TPMULTICONTEXTS flag set, a new application association is created and is designated the current association for the thread. The Oracle Tuxedo domain to which the new association is made is determined by the value of the TUXCONFIG or WSENVFILE/WSNADDR environment variable.Many ATMI functions operate on a per-context basis. (For a complete list, see “Using Per-context Functions and Data Structures in a Multithreaded ATMI Client” on page 10‑44.) In such cases, the target context must be the current context. Although clients can join more than one context, at any time, in any thread, only one context can be the current context.In such situations, one client threads calls tpgetctxt(3c) and passes the handle that is returned (the value of which is the current context) to a second client thread. The second thread then associates itself with the current context by calling tpsetctxt(3c) and specifying the handle it received from tpgetctxt(3c) via the first thread.Once the second thread is associated with the desired context, it is available to perform tasks executed by ATMI functions that operate on a per-context basis. For details, see “Using Per-context Functions and Data Structures in a Multithreaded ATMI Client” on page 10‑44.A thread sends a request to a server by calling either tpcall(3c) for a synchronous request or tpacall(3c)for an asynchronous request. If the request is sent with tpcall(), then the reply is received without further action by any thread.If an asynchronous request for a service has been sent with tpcall(3c), a thread in the same context (which may or may not be the same thread that sent the request) gets the reply by calling tpgetrply(3c).If one thread of an application calls tpcommit(3c) concurrently with an RPC or conversational call in another thread of the application, the system acts as if the calls were issued in some serial order. An application context may temporarily suspend work on a transaction by calling tpsuspend(3c) and then start another transaction subject to the same restrictions that exist for single-threaded and single-context programs.
Use dedicated thread notification.
(available only for C applications)
• If your application runs on a platform that supports multicontexting but not multithreading, then you cannot use the TPU_THREAD unsolicited notification method. As a result, you cannot receive immediate notification of events.If tpinit(3c) is called on a platform for which the Oracle Tuxedo system does not support threads, with parameters indicating that TPU_THREAD notification is being requested on a platform that does not support threads, tpinit() returns -1 and sets tperrno to TPEINVAL. If the UBBCONFIG(5) default NOTIFY option is set to THREAD but threads are not available on a particular machine, the default behavior for that machine is downgraded to DIPIN. The difference between these two behaviors allows an administrator to specify a default for all machines in a mixed configuration—a configuration that includes some machines that support threads and some that do not—but it does not allow a client to explicitly request a behavior that is not available on its machine.If tpsetunsol(3c)is called from a thread that is not associated with a context, a per-process default unsolicited message handler for all new tpinit(3c) 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.If a process has multiple associations with the same application, then each association is assigned a different CLIENTID so that it is possible to send an unsolicited message to a specific application association. If a process has multiple associations with the same application, then any tpbroadcast(3c) is sent separately to each of the application associations that meet the broadcast criteria. When performing a dip-in check for receiving unsolicited messages, an application checks for only those messages sent to the current application association.In addition to the ATMI functions permitted in unsolicited message handlers, it is permissible to call tpgetctxt(3c) within an unsolicited message handler. This functionality allows an unsolicited message handler to create another thread to perform any more substantial ATMI work required within the same context.For each thread in each application, userlog(3c) records the following identifying information:Placeholders are printed in the thread_ID and context_ID fields of entries for non-threaded platforms and single-contexted applications.The TM_MIB(5) supports this functionality in the TA_THREADID and TA_CONTEXTID fields in the T_ULOG class.In this phase, when the client process is about to exit, on behalf of the current context and all associated threads, a thread ends its application association by calling tpterm(3c). Like other ATMI functions, tpterm() operates on the current context. It affects all threads for which the context is set to the terminated context, and terminates any commonality of context among these threads.A well-designed application normally waits for all work in a particular context to complete before it calls tpterm(). Be sure that all threads are synchronized before your application calls tpterm().What happens during the start-up phase depends on the value of the MINDISPATCHTHREADS and MAXDISPATCHTHREADS parameters in the configuration file.
If the value of MINDISPATCHTHREADS is . . . And the value of MAXDISPATCHTHREADS
is . . .
2. The dispatcher calls tpsvrinit(3c) to join the application.
2. The dispatcher calls tpsvrinit(3c) to join the application.
4. Each new system-created thread calls tpsvrthrinit(3c) to join the application.
• If necessary, additional threads (up to the number indicated by MAXDISPATCHTHREADS) are created.In response to clients’ requests for a service, the server dispatcher creates multiple threads (up to a configurable maximum) in one server that can be assigned to various client requests concurrently. A server cannot become a client by calling tpinit(3c).This functionality is controlled by the following parameters in the SERVERS section of the UBBCONFIG(5) file and the TM_MIB(5).
• Each dispatched thread is created with the stack size specified by THREADSTACKSIZE (or TA_THREADSTACKSIZE). If this parameter is not specified or has a value of 0, the operating system default is used. On a few operating systems on which the default is too small to be used by the Oracle Tuxedo system, a larger default is used.
• If the value of this parameter is not specified or is 0, or if the operating system does not support setting a THREADSTACKSIZE, then the operating system default is used.
• MINDISPATCHTHREADS (or TA_MINDISPATCHTHREADS) must be less than or equal to MAXDISPATCHTHREADS (or TA_MAXDISPATCHTHREADS).
• If MAXDISPATCHTHREADS (or TA_MAXDISPATCHTHREADS) is 1, then the dispatcher thread and the service function thread are the same thread.
• If MAXDISPATCHTHREADS (or TA_MAXDISPATCHTHREADS) is greater than 1, any separate thread used for dispatching other threads does not count toward the limit of dispatched threads.
•
•
• Initially, application-created server threads are not associated with any server dispatch context. An application-created server thread may call tpsetctxt(3c) (and pass it a value returned by a previous call to tpgetctxt(3c) within a server-dispatched thread) to associate itself with that server-dispatched context.
• An application-created server thread cannot call tpreturn(3c) or tpforward(3c). When an application-created server thread has finished its work, it must call tpsetctxt(3c) with the context set to TPNULLCONTEXT before the originally dispatched thread calls tpreturn().
• Number of server-dispatched threads currently in use (TA_CURDISPATCHTHREADS)
•
• Number of server-dispatched threads historically started (TA_NUMDISPATCHTHREADS)For each thread in each application, userlog(3c) records the following identifying information:Placeholders are printed in the thread_ID and context_ID fields of entries for non-threaded platforms and single-contexted applications.The TM_MIB(5) supports this functionality in the TA_THREADID and TA_CONTEXTID fields in the T_ULOG class.When the application is shut down, tpsvrthrdone(3c) and tpsvrdone(3c) are called to perform any termination processing that is necessary, such as closing a resource manager.
• Do you need to set any parameters required by your RM to enable multithreaded access by your servers? For example, if you use an Oracle database with a multithreaded application, you must set the THREADS=true parameter as part of the OPENINFO string passed to Oracle. By doing so, you make it possible for individual threads to operate as separate Oracle associations.
Multithreading. Assign a value greater than 1 to MAXDISPATCHTHREADS. This value enables multiple clients, each in its own thread, for the server.
• The Oracle Tuxedo system does not supply tools for creating threads, but it supports various threads packages provided by different operating systems. To create and synchronize threads, you must use the functions native to your operating system. To find out which, if any, threads packages are supported by your operating system, see Installing the Oracle Tuxedo System.
• When multithreaded threads are operating on the same context, the programmer must ensure that functions are being executed in the required serial order. For example, all RPC calls and conversations must be compiled before tpcommit(3c) can be called. If tpcommit() is called from a thread other than the thread from which all these RPC or conversational calls are made, some concurrency control is probably required in the application.
• Similarly, it is permissible to call tpacall(3c) in one thread and tpgetrply(3c) in another, but the application must either:
•
•
• Multiple threads may operate on the same conversation but application programmers must realize that if different threads issue tpsend(3c) at approximately the same time, the system acts as though these tpsend() calls have been issued in an arbitrary order.If your application uses transactions, you should also keep in mind the consequences of multicontexting for transactions. For more information, see “Coding Rules for Transactions in a Multithreaded/Multicontexted ATMI Application” on page 10‑32.
Note:
• If an application-created server thread exits without changing context before the original dispatched thread exits, then tpreturn(3c) or tpforward(3c) fails. The execution of a thread exit does not automatically trigger a call to tpsetctxt(3c) to change the context to TPNULLCONTEXT.
• If you call tpinit(3c) more than once, either to join multiple applications or to make multiple connections to a single application, keep in mind that on each tpinit() you must accommodate whatever security mechanisms have been established.When a client is ready to join an application, specify tpiit(3c) with the TPMULTICONTEXTS flag set, as shown in the following sample code.#include <stdio.h>
#include <atmi.h>
TPINIT * tpinitbuf;
main()
{
tpinitbuf = tpalloc(TPINIT, NULL, TPINITNEED(0));
tpinitbuf->flags = TPMULTICONTEXTS;
.
.
.
if (tpinit (tpinitbuf) == -1) {
ERROR_PROCESSING_CODE
}
.
.
.
}A new application association is created and assigned to the Oracle Tuxedo domain specified in the TUXCONFIG or WSENVFILE/WSNADDR environment variable.
Note: In any one process, either all calls to tpinit(3c) must include the TPMULTICONTEXTS flag or else 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(3c), 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 you are ready to disconnect a client from an application, invoke tpterm(3c). Keep in mind, however, that in a multicontexted application tpterm() destroys the current context. All the threads operating on that context are affected. As the application programmer, you must carefully coordinate the use of multiple threads to make sure that tpterm() is not called unexpectedly.It is important to avoid calling tpterm(3c) on a context while other threads are still working on that context. If such a call to tpterm() is made, the Oracle Tuxedo system places the other threads that had been associated with that context in a special invalid context state. When in the invalid context state, most ATMI functions are disallowed. A thread may exit from the invalid context state by calling tpsetctxt(3c) or tpterm(). Most well designed applications never have to deal with the invalid context state.
1.
2.
4. Switch the value of the TUXCONFIG environment variable to the value required by the secondapp context, by calling tuxputenv().
5.
7.
8. Call firstapp services.
9.
10.
11.
12.
13. Listing 10‑2 Sample Code for Switching Contexts in a ClientIf tpsetunsol(3c) is called from a thread that is not associated with a context, a per-process default unsolicited message handler for all new tpinit(3c) 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.Set up the handler in the same way you set one up for a single-threaded or single-contexted application. See tpsetunsol(3c) for details.You can use tpgetctxt(3c) in an unsolicited message handler if you want to identify the context in which you are currently working.
•
• You can call tpcommit(3c) from only one thread in any particular transaction.
Note: The instructions and sample code provided in this section refer to the C library functions provided by the Oracle Tuxedo system. (See the Oracle Tuxedo C Function Reference for details.) Equivalent COBOL routines are not available because multithreading (which is required to create a multicontexted server) is not supported for COBOL applications.
• If an application-created server thread exits without changing context before the original dispatched thread exits, then tpreturn(3c) or tpforward(3c) fails. The execution of a thread exit does not automatically trigger a call to tpsetctxt(3c) to change the context to TPNULLCONTEXT.
• A server is prohibited from calling tpinit(3c) or otherwise acting as a client. If a server process calls tpinit(), tpinit() returns -1 and sets tperrno(5) to TPEPROTO. An application-created server thread may not make ATMI calls before calling tpsetctxt(3c).
• A server cannot execute a tpreturn(3c) or tpforward(3c) if any application-created thread is still associated with any application context. Therefore, before a server-dispatched thread calls tpreturn(), each application-created thread associated with that context must call tpsetctxt(3c) with the context set to either TPNULLCONTEXT or another valid context.If this rule is violated, then tpreturn(3c) or tpforward(3c) writes a message to the user log, indicates TPESVCERR to the caller, and returns control to the main server dispatch loop. The threads that had been in the context where the invalid tpreturn() was done are placed in an invalid context.
• If there are outstanding ATMI calls, RPC calls, or conversations when tpreturn(3c) or tpforward(3c) is called, tpreturn() or tpforward() writes a message to the user log, indicates TPESVCERR to the caller, and returns control to the main server dispatch loop.
Initially, application-created server threads are not associated with any server-dispatched context. If called before being initialized, however, most ATMI functions perform an implicit tpinit(3c). Such calls introduce problems because servers are prohibited from calling tpinit(). (If a server process calls tpinit(), tpinit() returns -1 and sets tperrno(5) to TPEPROTO.)
2. Server-dispatched-thread_A passes the handle returned by tpgetctxt(3c) to Application_thread_B.
3. Application_thread_B associates itself with the current context by calling tpsetctxt(3c), specifying the handle received from Server-dispatched-thread_A.
4. Application-created server threads cannot call tpreturn(3c) or tpforward(3c). Before the originally dispatched thread calls tpreturn() or tpforward(), all application-created server threads that have been in that context must switch to TPNULLCONTEXT or another valid context.If this rule is not observed, then tpforward(3c) or tpreturn(3c) fails and indicates a service error to the caller.
Notes: In order to simplify the sample, error checking code is not included. Also, an example of a multicontexted server using only threads dispatched by the Oracle Tuxedo system is not included because such a server is coded in exactly the same way as a single-contexted server, as long as thread-safe programming practices are used.The previous example accomplishes a funds transfer by invoking the DEPOSIT service in the originally dispatched thread, and WITHDRAWAL in an application-created thread. This example is based on the assumption that the resource manager being used allows a mixed model such that multiple threads of a server can be associated with a particular database connection without all threads of the server being associated with that instance. Most resource managers, however, do not support such a model.A simpler way to code this example is to avoid the use of an application-created thread. To obtain the same concurrency provided by the two calls to tpcall(3c) in the example, substitute two calls to tpacall(3c) and two calls to tpgetrply(3c) in the server-dispatched thread.
• Any thread operating in the same context within the same process can invoke tpgetrply(3c) to receive a response to an earlier call to tpacall(3c), regardless of whether or not that thread originally called tpacall().
• All RPC calls and conversations must be completed before an attempt is made to commit the transaction. If an application calls tpcommit(3c) while RPC calls or conversations are outstanding, tpcommit() aborts the transaction, returns -1, and sets tperrno(5) to TPEABORT.
• Functions such as tpcall(3c), tpacall(3c), tpgetrply(3c), tpconnect(3c), tpsend(3c), tprecv(3c), and tpdiscon(3c) should not be called in transaction mode unless you are sure that the transaction is not already committing or aborting.
• Two tpbegin(3c) calls cannot be made simultaneously for the same context.
• tpbegin(3c) cannot be issued for a context that is already in transaction mode.
• If you are using a client and you want to connect to more than one domain, you must manually change the value of TUXCONFIG or WSNADDR before calling tpinit(3c). You must synchronize the setting of the environment variable and the tpinit() call if multiple threads may be performing such an action. All application associations in a client must obey the following rules:
• To join an application, a multithreaded Workstation client must always call tpinit(3c) with the TPMULTICONTEXTS flag set, even if the client is running in single-context mode.To have a client join more than one context, issue a call to the tpinit(3c) function with the TPMULTICONTEXTS flag set in the flags element of the TPINIT data structure.In any one process, either all calls to tpinit(3c) 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(3c), 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(3c) is invoked with the TPMULTICONTEXTS flag set, a new application association is created and is designated the current association. The Oracle 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(3c) without the TPMULTICONTEXTS flag, all threads in the client are placed in the single-context state (TPSINGLECONTEXT).On failure, tpinit(3c) 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(3c) from a given context if any of the threads in that context are still working. See the table labeled “Multicontext State Transitions” on page 10‑40 for a description of the context states that result from calling tpterm() under these and other circumstances.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. Figure 10‑4 illustrates the context state changes that result from calls to tpinit(3c), tpsetctxt(3c), and tpterm(3c). (The tpgetctxt(3c) function does not produce any context state changes.)Figure 10‑4 Multicontext State Transitions
Note: When tpterm(3c) 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).Table 10‑2 lists all possible context state changes produced by calling tpinit(3c), tpsetctxt(3c), and tpterm(3c).
Table 10‑2 Context State Changes for a Client Thread tpinit(3c) without TPMULTICONTEXTS tpinit(3c) with TPMULTICONTEXTS tpsetctxt(3c) to TPNULLCONTEXT tpsetctxt(3c) to context 0 tpsetctxt(3c) to context > 0 tpterm(3c) in this thread tpterm(3c) in a different thread of this context tpgetrply(3c) receives responses only to requests made via tpacall(3c). Requests made with tpcall(3c) are separate and cannot be retrieved with tpgetrply() regardless of the multithreading or multicontexting level.tpgetrply(3c) 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(3c) is called in a multithreaded environment, the following restrictions apply:
• If a thread calls tpgetrply(3c) for a specific handle while another thread in the same context is already waiting in tpgetrply() for the same handle, tpgetrply() returns -1 and sets tperrno to TPEPROTO.
• If a thread calls tpgetrply(3c) for a specific handle while another thread in the same context is already waiting in tpgetrply() with the TPGETANY flag, the call returns -1 and sets tperrno(5) to TPEPROTO.The same behavior occurs if a thread calls tpgetrply(3c) 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.
• At any given time, only one thread in a particular context can wait in tpgetrply(3c) with the TPGETANY flag set. If a second thread in the same context invokes tpgetrply() with the TPGETANY flag while a similar call is outstanding, this second call returns -1 and sets tperrno(5) to TPEPROTO.
FIELDTBLS and FIELDTBLS32 FLDTBLDIR and FLDTBLDIR32 VIEWDIR and VIEWDIR32 VIEWFILES and VIEWFILES32
• The tuxputenv(3c) function affects the environment for the entire process.
• When you call the tuxreadenv(3c) function, it reads a file containing environment variables and adds them to the environment for the entire process.
• The tuxgetenv(3c) function returns the current value of the requested environment variable in the current context. Initially, all contexts have the same environment, but the use of environment files specific to a particular context can cause different contexts to have different environment settings.
• If a client intends to initialize to more than one domain, the client must change the value of the TUXCONFIG, WSNADDR, or WSENVFILE environment variable to the proper value before each call to tpinit(3c). If such an application is multithreaded, a mutex or other application-defined concurrency control will probably be needed to ensure that:
• The call to tpinit(3c) is made without the environment variable being reset by any other thread.
• When a client initializes to the system, the WSENVFILE and/or machine environment file is read and affects the environment in that context only. The previous environment for the process as a whole remains for that context to the extent that it is not overridden within the environment file(s).
Note: For tpbroadcast(3c), 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(3c).If tpsetunsol(3c) is called from a thread that is not associated with a context, a per-process default unsolicited message handler for all new tpinit(3c) 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.
• The CLIENTID, client name, username, transaction ID, and the contents of the TPSVCINFO data structure may differ from context to context within the same process.
• tpconvert(3c)—the requested structure is converted, although it is probably relevant to only a subset of the process.
• tpinit(3c)—to the extent that the per-process TPMULTICONTEXTS mode or single-context mode is established. See also “Using Per-context Functions and Data Structures in a Multithreaded ATMI Client” on page 10‑44.
• tuxgetenv(3c)—if the OS environment is per-process.
• tuxputenv(3c)—if the OS environment is per-process.
• tuxreadenv(3c)—if the OS environment is per-process.
•
• The Ferror, Ferror32(5), tperrno(5), tpurcode(5), and Uunix_err variables are specific to each thread.Listing 10‑4 Sample Code for a Multithreaded ClientMultithreaded servers are almost always multicontexted, as well. For information about writing a multithreaded server, see “Writing Code to Enable Multicontexting and Multithreading in an ATMI Server” on page 10‑33.The programs provided by the Oracle Tuxedo system for compiling or building executables, such as buildserver(1) and buildclient(1), automatically include any required compiler flags. If you use these tools, then you do not need to set any flags at compile time.If, however, you compile your .c files into .o files before doing a final compilation, you may need to set platform-specific compiler flags. Such flags must be set consistently for all code linked into a single process.If you are creating a multithreaded server, you must run the buildserver(1) command with the -t option. This option is mandatory for multithreaded servers; if you do not specify it at build time and later try to boot the new server with a configuration file in which the value of MAXDISPATCHTHREADS is greater than 1, a warning message is recorded in the user log and the server reverts to single-threaded operation.To identify any operating system-specific compiler parameters that are required when you compile .c files into .o files in a multithreaded environment, run buildclient(1) or buildserver(1) with the -v option set on a test file.When you need to investigate possible causes of errors, we recommend that you start by checking whether and how the TPMULTICONTEXTS flag has been set. Errors are frequently introduced by failures to set this flag or to set it properly.If a process includes the TPMULTICONTEXTS flag in a state for which this flag is not allowed (or omits TPMULTICONTEXTS in a state that requires it), then tpinit(3c) returns -1 and sets tperrno to TPEPROTO.When tpinit(3c) is invoked without TPMULTICONTEXTS, it behaves as it does when called in a single-contexted application. When tpinit() has been invoked once, subsequent tpinit() calls without the TPMULTICONTEXTS flag succeed without further action. This is true even if the value of the TUXCONFIG or WSNADDR environment variable in the application has been changed. Calling tpinit() without the TPMULTICONTEXTS flag set is not allowed in multicontext mode.If a client has not joined an application and tpinit(3c) is called implicitly (as a result of a call to another function that calls tpinit()), then the Oracle Tuxedo system interprets the action as a call to tpinit() without the TPMULTICONTEXTS flag for purposes of determining which flags may be used in subsequent calls to tpinit().For most ATMI functions, if a function is invoked by a thread that is not associated with a context in a process already operating in multicontext mode, the ATMI function fails with tperrno(5)=TPEPROTO.On Compaq Tru64 UNIX and other systems on which POSIX threads are used, a thread stack size is specified by invoking pthread_attr_setstacksize() before calling pthread_create(). On UnixWare, the thread stack size is specified as an argument to thr_create(). Consult your operating system documentation for further information on this subject.