PThread API Reference
PThread API Reference
Complete Pthread API list Thread management APIs Thread specific storage APIs Thread cancellation APIs Mutex synchronization API Condition variable synchronization APIs Read/write lock synchronization APIs Signals APIs
Before you get started with Pthreads Many details in Multithreaded applications will affect your interpretation of how the Pthread APIs work. Multithreaded applications also contains important general information about threads. The information includes how process architecture and process behavior change when running a threaded program, what parts of the system are not available for use when running a threaded program, and tips on performance and debugging of threaded jobs. Programming with Pthreads
q
What are Pthreads? Primitive data types -- Naming conventions for primitive data types in threaded programs. Feature test macros -- Descriptions of supported and unsupported feature test macros. OS/400 Pthreads versus other threads implementations Using header files for Pthread functions Pthread glossary -- Definitions of some common Pthread terms. Other sources of Pthread information Writing and compiling threaded programs Running threaded programs
Pthread programming basic tasks -- Information to get you started with Pthreads programming.
r r
Troubleshooting Pthread errors -- Descriptions of common errors users encounter when programming with Pthreads.
pthread_atfork()--Register Fork Handlers pthread_atfork_np()--Register Fork Handlers with Extended Options pthread_attr_destroy()--Destroy Thread Attributes Object pthread_attr_getdetachstate()--Get Thread Attributes Object Detachstate pthread_attr_getinheritsched()--Get Thread Attribute Object Inherit Scheduling Attributes pthread_attr_getschedparam()--Get Thread Attributes Object Scheduling Parameters pthread_attr_getschedpolicy()--Get Scheduling Policy pthread_attr_getscope()--Get Scheduling Scope pthread_attr_getstackaddr()--Get Stack Address pthread_attr_getstacksize()--Get Stack Size pthread_attr_init()--Initialize Thread Attributes Object pthread_attr_setdetachstate()--Set Thread Attributes Object Detachstate pthread_attr_setinheritsched()--Set Thread Attribute Inherit Scheduling Attributes pthread_attr_setschedparam()--Set Thread Attributes Object Scheduling Parameters pthread_attr_setschedpolicy()--Set Scheduling Policy pthread_attr_setscope()--Set Scheduling Scope pthread_attr_setstackaddr()--Set Stack Address pthread_attr_setstacksize()--Set Stack Size pthread_cancel()--Cancel Thread pthread_cleanup_peek_np()--Copy Cleanup Handler from Cancellation Cleanup Stack pthread_cleanup_pop()--Pop Cleanup Handler off of Cancellation Cleanup Stack pthread_cleanup_push()--Push Cleanup Handler onto Cancellation Cleanup Stack pthread_clear_exit_np()--Clear Exit Status of Thread pthread_cond_broadcast()--Broadcast Condition to All Waiting Threads pthread_cond_destroy()--Destroy Condition Variable pthread_cond_init()--Initialize Condition Variable pthread_cond_signal()--Signal Condition to One Waiting Thread pthread_cond_timedwait()--Timed Wait for Condition pthread_cond_wait()--Wait for Condition pthread_condattr_destroy()--Destroy Condition Variable Attributes Object pthread_condattr_init()--Initialize Condition Variable Attributes Object pthread_condattr_getpshared()--Get Process Shared Attribute from Condition Attributes Object pthread_condattr_setpshared()--Set Process Shared Attribute in Condition Attributes Object
pthread_create()--Create Thread pthread_delay_np()--Delay Thread for Requested Interval pthread_detach()--Detach Thread pthread_equal()--Compare Two Threads pthread_exit()--Terminate Calling Thread pthread_extendedjoin_np()--Wait for Thread with Extended Options pthread_get_expiration_np()--Get Condition Expiration Time from Relative Time pthread_getcancelstate_np()--Get Cancel State pthread_getconcurrency()--Get Process Concurrency Level pthread_getpthreadoption_np()--Get Pthread Run-Time Option Data pthread_getschedparam()--Get Thread Scheduling Parameters pthread_getspecific()--Get Thread Local Storage Value by Key pthread_getthreadid_np()--Retrieve Unique ID for Calling Thread pthread_getunique_np()--Retrieve Unique ID for Target Thread pthread_is_initialthread_np()--Check if Running in the Initial Thread pthread_is_multithreaded_np()--Check Current Number of Threads pthread_join()--Wait for and Detach Thread pthread_join_np()--Wait for Thread to End pthread_key_create()--Create Thread Local Storage Key pthread_key_delete()--Delete Thread Local Storage Key pthread_kill()--Send Signal to Thread pthread_lock_global_np()--Lock Global Mutex pthread_mutex_destroy()--Destroy Mutex pthread_mutex_getprioceiling()--Get Mutex Priority Ceiling pthread_mutex_init()--Initialize Mutex pthread_mutex_lock()--Lock Mutex pthread_mutex_setprioceiling()--Set Mutex Priority Ceiling pthread_mutex_timedlock_np()--Lock Mutex with Time-Out pthread_mutex_trylock()--Lock Mutex with No Wait pthread_mutex_unlock()--Unlock Mutex pthread_mutexattr_destroy()--Destroy Mutex Attributes Object pthread_mutexattr_getkind_np()--Get Mutex Kind Attribute pthread_mutexattr_getname_np()--Get Name from Mutex Attributes Object pthread_mutexattr_getprioceiling()--Get Mutex Priority Ceiling Attribute pthread_mutexattr_getprotocol()--Get Mutex Protocol Attribute pthread_mutexattr_getpshared()--Get Process Shared Attribute from Mutex Attributes Object pthread_mutexattr_gettype()--Get Mutex Type Attribute pthread_mutexattr_init()--Initialize Mutex Attributes Object
pthread_mutexattr_setkind_np()--Get Mutex Kind Attribute pthread_mutexattr_setname_np()--Set Name in Mutex Attributes Object pthread_mutexattr_setprioceiling()--Set Mutex Priority Ceiling Attribute pthread_mutexattr_setprotocol()--Set Mutex Protocol Attribute pthread_mutexattr_setpshared()--Set Process Shared Attribute in Mutex Attributes Object pthread_mutexattr_settype()--Set Mutex Type Attribute pthread_once()--Perform One-Time Initialization pthread_rwlock_destroy()--Destroy Read/Write Lock pthread_rwlock_init()--Initialize Read/Write Lock pthread_rwlock_rdlock()--Get Shared Read Lock pthread_rwlock_timedrdlock_np()--Get Shared Read Lock with Time-Out pthread_rwlock_timedwrlock_np()--Get Exclusive Write Lock with Time-Out pthread_rwlock_tryrdlock()--Get Shared Read Lock with No Wait pthread_rwlock_trywrlock()--Get Exclusive Write Lock with No Wait pthread_rwlock_unlock()--Unlock Exclusive Write or Shared Read Lock pthread_rwlock_wrlock()--Get Exclusive Write Lock pthread_rwlockattr_destroy()--Destroy Read/Write Lock Attribute pthread_rwlockattr_getpshared()--Get Pshared Read/Write Lock Attribute pthread_rwlockattr_init()--Initialize Read/Write Lock Attribute pthread_rwlockattr_setpshared()--Set Pshared Read/Write Lock Attribute pthread_self()--Get Pthread Handle pthread_set_mutexattr_default_np()--Set Default Mutex Attributes Object Kind Attribute pthread_setcancelstate()--Set Cancel State pthread_setcanceltype()--Set Cancel Type pthread_setconcurrency()--Set Process Concurrency Level pthread_setpthreadoption_np()--Set Pthread Run-Time Option Data pthread_setschedparam()--Set Target Thread Scheduling Parameters pthread_setspecific()--Set Thread Local Storage by Key pthread_sigmask()--Set or Get Signal Mask pthread_signal_to_cancel_np()--Convert Signals to Cancel Requests pthread_test_exit_np()--Test Thread Exit Status pthread_testcancel()--Create Cancellation Point pthread_trace_init_np()--Initialize or Reinitialize Pthread Tracing PTHREAD_TRACE_NP()--Macro to optionally execute code based on trace level pthread_unlock_global_np()--Unlock Global Mutex sched_yield()--Yield Processor to Another Thread
contentionscope PTHREAD_SCOPE_SYSTEM PTHREAD_EXPLICIT_SCHED, priority inheritsched equal PRIORITY_DEFAULT (0) schedpolicy SCHED_OTHER
For information about the examples included with the APIs, see the information on the API examples. The thread management APIs are:
q q q q q q q q q q q q q q q q q q q q
pthread_attr_destroy()--Destroy Thread Attributes Object pthread_attr_getdetachstate()--Get Thread Attributes Object Detachstate pthread_attr_getinheritsched()--Get Thread Attribute Object Inherit Scheduling Attributes pthread_attr_getschedparam()--Get Thread Attributes Object Scheduling Parameters pthread_attr_init()--Initialize Thread Attributes Object pthread_attr_setdetachstate()--Set Thread Attributes Object Detachstate pthread_attr_setinheritsched()--Set Thread Attribute Inherit Scheduling Attributes pthread_attr_setschedparam()--Set Thread Attributes Object Scheduling Parameters pthread_clear_exit_np()--Clear Exit Status of Thread pthread_create()--Create Thread pthread_delay_np()--Delay Thread for Requested Interval pthread_detach()--Detach Thread pthread_equal()--Compare Two Threads pthread_exit()--Terminate Calling Thread pthread_extendedjoin_np()--Wait for Thread with Extended Options pthread_getconcurrency()--Get Process Concurrency Level pthread_getpthreadoption_np()--Get Pthread Run-Time Option Data pthread_getschedparam()--Get Thread Scheduling Parameters pthread_getthreadid_np()--Retrieve Unique ID for Calling Thread pthread_getunique_np()--Retrieve a Unique ID for Target Thread
pthread_is_initialthread_np()--Check if Running in the Initial Thread pthread_is_multithreaded_np()--Check the Current Number of Threads pthread_join()--Wait for and Detach Thread pthread_join_np()--Wait for Thread to End pthread_once()--Perform One-Time Initialization pthread_self()--Get Pthread Handle pthread_setconcurrency()--Set Process Concurrency Level pthread_setpthreadoption_np()--Set Pthread Run-Time Option Data pthread_setschedparam()--Set Target Thread Scheduling Parameters pthread_trace_init_np()--Initialize or Reinitialize Pthread Tracing PTHREAD_TRACE_NP()--Execute Code Based on Trace Level (Macro) sched_yield()--Yield Processor to Another Thread
Parameters
attr (Input) The address of the thread attributes object to be destroyed
Return Value
0 pthread_attr_destroy() was successful. value pthread_attr_destroy() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_attr_destroy() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] Invalid Argument Specified
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_attr_init()--Initialize Thread Attributes Object
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void *threadfunc(void *parm) {
printf("Thread created using an default attributes\n"); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; pthread_attr_t pta; printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread attributes object\n"); rc = pthread_attr_init(&pta); checkResults("pthread_attr_init()\n", rc); printf("Create a thread using the attributes object\n"); rc = pthread_create(&thread, &pta, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Create a thread using the default attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Destroy thread attributes object\n"); rc = pthread_attr_destroy(&pta); checkResults("pthread_attr_destroy()\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(5); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TAINI0 Create a thread attributes object Create a thread using the attributes object Create a thread using the default attributes Destroy thread attributes object Thread created using an default attributes Thread created using an default attributes Main completed
Parameters
attr (Input) The address of the thread attributes object detachstate (Output) The address of the variable to contain the returned detach state
Return Value
0 pthread_attr_getdetachstate() was successful. value pthread_attr_getdetachstate() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_attr_getdetachstate() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_attr_setdetachstate()--Set Thread Attributes Object Detachstate pthread_detach()--Detach Thread pthread_join()--Wait for and Detach Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" int main(int argc, char **argv) { pthread_t thread; int rc=0; pthread_attr_t pta; int state; printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread attributes object\n"); rc = pthread_attr_init(&pta); checkResults("pthread_attr_init()\n", rc); printf("Get detach state\n"); rc = pthread_attr_getdetachstate(&pta, &state); checkResults("pthread_attr_getdetachstate()\n", rc); printf("The thread attributes object indicates: "); switch (state) { case PTHREAD_CREATE_DETACHED: printf("DETACHED\n"); break; case PTHREAD_CREATE_JOINABLE: printf("JOINABLE\n"); break; } printf("Destroy thread attributes object\n"); rc = pthread_attr_destroy(&pta); checkResults("pthread_attr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TAGDS0 Create a thread attributes object Get detach state The thread attributes object indicates: JOINABLE Destroy thread attributes object Main completed
Parameters
attr (Input) Address of thread creation attributes inheritsched (Output) Address of the variable to receive the inheritsched attribute
Return Value
0 pthread_attr_getinheritsched() was successful. value pthread_attr_getinheritsched() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_attr_getinheritsched() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_attr_setinheritsched()--Set Thread Attribute Inherit Scheduling Attributes
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <except.h> #include "check.h" void showInheritSched(pthread_attr_t *attr) { int rc; int inheritsched; rc = pthread_attr_getinheritsched(attr, &inheritsched); checkResults("pthread_attr_getinheritsched()\n", rc); switch(inheritsched) { case PTHREAD_EXPLICIT_SCHED: printf("Inherit Sched - PTHREAD_EXPLICIT_SCHED\n"); break; case PTHREAD_INHERIT_SCHED: printf("Inherit Sched - PTHREAD_INHERIT_SCHED\n"); break; default: printf("Invalid inheritsched attribute!\n"); exit(1); } return; } int main(int argc, char **argv) { pthread_t thread; int rc=0; pthread_attr_t attr; char c; void *status; printf("Enter Testcase - %s\n", argv[0]); rc = pthread_attr_init(&attr); checkResults("pthread_attr_init()\n", rc); showInheritSched(&attr); rc = pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); checkResults("pthread_attr_setinheritsched()\n", rc); showInheritSched(&attr); rc = pthread_attr_destroy(&attr); checkResults("pthread_attr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPGIS0 Inherit Sched - PTHREAD_EXPLICIT_SCHED Inherit Sched - PTHREAD_INHERIT_SCHED
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_g7.htm (2 of 3) [2/9/2001 1:56:32 PM]
Main completed
Parameters
attr (Input) The address of the thread attributes object param (Output) The address of the variable to contain the returned scheduling parameters
Return Value
0 pthread_attr_getschedparam() was successful. value pthread_attr_getschedparam() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_attr_getschedparam() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. The <sched.h> header file. See Header files for Pthread functions. pthread_attr_setschedparam()--Set Thread Attributes Object Scheduling Parameters.
Example
#define _MULTI_THREADED #include <pthread.h> #include <sched.h> #include <stdio.h> #include "check.h" int main(int argc, char { pthread_t int pthread_attr_t struct sched_param **argv) thread; rc=0; pta; param;
printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread attributes object\n"); rc = pthread_attr_init(&pta); checkResults("pthread_attr_init()\n", rc); printf("Get scheduling parameters\n"); rc = pthread_attr_getschedparam(&pta, ¶m); checkResults("pthread_attr_getschedparam()\n", rc); printf("The thread attributes object indicates: "); printf("priority %d\n", param.sched_priority); printf("Destroy thread attributes object\n"); rc = pthread_attr_destroy(&pta); checkResults("pthread_attr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TAGSP0 Create a thread attributes object Get scheduling parameters The thread attributes object indicates: priority 0 Destroy thread attributes object Main completed
Parameters
attr (Input/Output) The address of the thread attributes object to be initialized
Return Value
0 pthread_attr_init() was successful. value pthread_attr_init() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_attr_init() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_attr_destroy()--Destroy Thread Attributes Object pthread_create()--Create Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void *threadfunc(void *parm)
{ printf("Thread created using an default attributes\n"); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; pthread_attr_t pta; printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread attributes object\n"); rc = pthread_attr_init(&pta); checkResults("pthread_attr_init()\n", rc); printf("Create a thread using the attributes object\n"); rc = pthread_create(&thread, &pta, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Create a thread using the default attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Destroy thread attributes object\n"); rc = pthread_attr_destroy(&pta); checkResults("pthread_attr_destroy()\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(5); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TAINI0 Create a thread attributes object Create a thread using the attributes object Create a thread using the default attributes Destroy thread attributes object Thread created using an default attributes Thread created using an default attributes Main completed
Parameters
attr (Input) The address of the thread attributes object. detachstate (Output) The detach state, one of PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.
Return Value
0 pthread_attr_setdetachstate() was successful. value pthread_attr_setdetachstate() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_attr_setdetachstate() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_attr_getdetachstate()--Get Thread Attributes Object Detachstate pthread_detach()--Detach Thread pthread_join()--Wait for and Detach Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void showDetachState(pthread_attr_t *a) { int rc=0; int state=0; printf("Get detach state\n"); rc = pthread_attr_getdetachstate(a, &state); checkResults("pthread_attr_getdetachstate()\n", rc); printf("The thread attributes object indicates: "); switch (state) { case PTHREAD_CREATE_DETACHED: printf("DETACHED\n"); break; case PTHREAD_CREATE_JOINABLE: printf("JOINABLE\n"); break; } return; } int main(int argc, char **argv) { pthread_t thread; int rc=0; pthread_attr_t pta; printf("Enter Testcase - %s\n", argv[0]); printf("Create a default thread attributes object\n"); rc = pthread_attr_init(&pta); checkResults("pthread_attr_init()\n", rc); showDetachState(&pta); printf("Set the detach state\n"); rc = pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_DETACHED); checkResults("pthread_attr_setdetachstate()\n", rc); showDetachState(&pta); printf("Destroy thread attributes object\n"); rc = pthread_attr_destroy(&pta); checkResults("pthread_attr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TASDS0 Create a default thread attributes object Get detach state The thread attributes object indicates: JOINABLE Set the detach state Get detach state The thread attributes object indicates: DETACHED Destroy thread attributes object Main completed
Parameters
attr (Input) Address of thread creation attributes inheritsched (Output) Address of the variable to receive the inheritsched attribute
Return Value
0 pthread_attr_setinheritsched() was successful value pthread_attr_setinheritsched() was not successful. value is set to indicate the error condition
Error Conditions
If pthread_attr_setinheritsched() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_attr_getinheritsched()--Get Thread Attribute Object Inherit Scheduling Attributes pthread_attr_getschedparam()--Get Thread Attributes Object Scheduling Parameters
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <except.h> #include "check.h" void showInheritSched(pthread_attr_t *attr) { int rc; int inheritsched; rc = pthread_attr_getinheritsched(attr, &inheritsched); checkResults("pthread_attr_getinheritsched()\n", rc); switch(inheritsched) { case PTHREAD_EXPLICIT_SCHED: printf("Inherit Sched - PTHREAD_EXPLICIT_SCHED\n"); break; case PTHREAD_INHERIT_SCHED: printf("Inherit Sched - PTHREAD_INHERIT_SCHED\n"); break; default: printf("Invalid inheritsched attribute!\n"); exit(1); } return; } int main(int argc, char **argv) { pthread_t thread; int rc=0; pthread_attr_t attr; char c; void *status; printf("Enter Testcase - %s\n", argv[0]); rc = pthread_attr_init(&attr); checkResults("pthread_attr_init()\n", rc); showInheritSched(&attr); rc = pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); checkResults("pthread_attr_setinheritsched()\n", rc); showInheritSched(&attr); rc = pthread_attr_destroy(&attr); checkResults("pthread_attr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPSIS0 Inherit Sched - PTHREAD_EXPLICIT_SCHED Inherit Sched - PTHREAD_INHERIT_SCHED
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_11.htm (2 of 3) [2/9/2001 1:56:33 PM]
Main completed
Parameters
attr (Input/Output) The address of the thread attributes object param (Input) Address of the variable containing the scheduling parameters
Return Value
0 pthread_attr_setschedparam() was successful. value pthread_attr_setschedparam() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_attr_setschedparam() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ENOTSUP] The value specified for the priority argument is not supported.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. The <sched.h> header file. See Header files for Pthread functions. pthread_attr_getschedparam()--Get Thread Attributes Object Scheduling Parameters
Example
#define _MULTI_THREADED #include <pthread.h> #include <sched.h> #include <stdio.h> #include "check.h" #define BUMP_PRIO 1 static int thePriority = 0; void showSchedParam(pthread_attr_t *a) { int rc=0; struct sched_param param; printf("Get scheduling parameters\n"); rc = pthread_attr_getschedparam(a, ¶m); checkResults("pthread_attr_getschedparam()\n", rc); printf("The thread attributes object indicates priority: %d\n", param.sched_priority); thePriority = param.sched_priority; return; } int main(int argc, char { pthread_t int pthread_attr_t struct sched_param **argv) thread; rc=0; pta; param;
printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread attributes object\n"); rc = pthread_attr_init(&pta); checkResults("pthread_attr_init()\n", rc); showSchedParam(&pta); memset(¶m, 0, sizeof(param)); if (thePriority + BUMP_PRIO <= PRIORITY_MAX_NP) { param.sched_priority = thePriority + BUMP_PRIO; } printf("Setting scheduling parameters\n"); rc = pthread_attr_setschedparam(&pta, ¶m); checkResults("pthread_attr_setschedparam()\n", rc); showSchedParam(&pta);
printf("Destroy thread attributes object\n"); rc = pthread_attr_destroy(&pta); checkResults("pthread_attr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TASSP0 Create a thread attributes object Get scheduling parameters The thread attributes object indicates priority: 0 Setting scheduling parameters Get scheduling parameters The thread attributes object indicates priority: 0 Destroy thread attributes object Main completed
Parameters
None.
Return Value
0 pthread_clear_exit_np() was successful. value pthread_clear_exit_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_clear_exit_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The thread is not currently exiting
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_exit()--Terminate Calling Thread pthread_cancel()--Cancel Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <except.h> #include <setjmp.h> #include "check.h" int threadStatus=1;
void cleanupHandler(void *p) { jmp_buf *j = (jmp_buf *)p; /* Warning, it is quite possible that using combinations of */ /* setjmp(), longjmp(), pthread_clear_exit_np(), and */ /* pthread_setcancelstate() to handle thread exits or */ /* cancellation could result in looping or non-cancelable */ /* threads if done incorrectly. */ printf("In cancellation cleanup handler. Handling the thread exit\n"); longjmp(*j, 1); printf("The exit/cancellation was not stopped!\n"); return; } void *threadfunc(void *parm) { jmp_buf j; int rc, old; printf("Inside secondary thread\n"); if (setjmp(j)) { /* Returned from longjmp after stopping the thread exit */ /* Since longjmp was called from within the cancellation */ /* cleanup handler, we must clear the exit state of the */ /* thread and reset the cancelability state to what it was */ /* before the cancellation cleanup handlers were invoked */ /* (Cancellation cleanup handlers are invoked with */ /* thread cancellation disabled) */ printf("Stopped the thread exit, now clean up the states\n"); printf("Clear exit state\n"); rc = pthread_clear_exit_np(); checkResults("pthread_clear_exit_np()\n", rc); printf("Restore cancel state\n"); rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old); checkResults("pthread_setcancelstate()\n", rc); /* This example was successful threadStatus = 0;
*/
} else { printf("Pushing cleanup handler that will stop the exit\n"); pthread_cleanup_push(cleanupHandler, &j); /* This exit will be stopped by cleanupHandler2 and the */ /* pthread_clear_exit_np() that is done above */ pthread_exit(__VOID(threadStatus)); printf("Did not expect to get here! Left status as 1.\n"); pthread_cleanup_pop(0);
} pthread_exit(__VOID(threadStatus)); } int main(int argc, char **argv) { pthread_t thread; int rc=0; char c; void *status; printf("Enter Testcase - %s\n", argv[0]); printf("Create thread that will demonstrate handling an exit\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(thread, &status); checkResults("pthread_join()\n", rc); if (__INT(status) != 0) { printf("Got an unexpected return status from the thread!\n"); exit(1); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPCEXIT0 Create thread that will demonstrate handling an exit Inside secondary thread Pushing cleanup handler that will stop the exit In cancellation cleanup handler. Handling the thread exit Stopped the thread exit, now clean up the states Clear exit state Restore cancel state Main completed
pthread_create()--Create Thread
pthread_create()--Create Thread
Syntax #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); Threadsafe: Yes Signal Safe: Yes The pthread_create() function creates a thread with the specified attributes and runs the C function start_routine in the thread with the single pointer argument specified. The new thread may, but does not always, begin running before pthread_create() returns. If pthread_create() completes successfully, the Pthread handle is stored in the contents of the location referred to by thread. If the start_routine returns normally, it is as if there was an implicit call to pthread_exit() using the return value of start_routine as the status. The function passed as start_routine should correspond to the following C function prototype: void *threadStartRoutinName(void *); If the thread attributes object represented by attr is modified later, the newly created thread is not affected. If attr is NULL, the default thread attributes are used. With the following declarations and initialization, pthread_t t; void *foo(void *); pthread_attr_t attr; pthread_attr_init(&pta); the following two thread creation mechanisms are functionally equivalent: rc = pthread_create(&t, NULL, foo, NULL); rc = pthread_create(&t, &attr, foo, NULL); The cancellation state of the new thread is PTHREAD_CANCEL_ENABLE. The cancellation type of the new thread is PTHREAD_CANCEL_DEFERRED. The signal information maintained in the new thread is as follows:
q q
The signal mask is inherited from the creating thread. The set of signals pending for the new thread is empty.
If you attempt to create a thread in a job that is not capable of starting threads, pthread_create() fails with the EBUSY error. If you attempt to create a thread from a location in which thread creation is not allowed, pthread_create() fails with the EBUSY error. See the pthread_getpthreadoption_np() function, option PTHREAD_OPTION_THREAD_CAPABLE_NP, for details about how to determine whether thread creation is currently allowed in your process. In the OS/400 implementation, the initial thread is special. Termination of the initial thread via pthread_exit() or any other thread termination mechanism terminates the entire process. The OS/400 implementation does not set a hard limit on the number of threads that can be created. The PTHREAD_THREADS_MAX macro is implemented as a function call, and returns different values depending on the administrative setting of the maximum number of threads for the process. The default is NO MAX and has the numeric value of 2147483647 (0x7FFFFFFF). Realistically, the number of threads is limited by the amount of storage available to the job. Currently, thread creation is not allowed after process termination has been started. For example, after a call to exit(), destructors for C++ static objects, functions registered with atexit() or CEE4RAGE() are allowed to run. If these functions attempt to create a thread, pthread_create() fails with the EBUSY error. Similar failures occur if other mechanisms are used to call pthread_create() after process termination has started.
pthread_create()--Create Thread
Usage Notes
1. If you attempt to create a thread in a job that is not capable of starting threads or for some other reason, thread creation is not allowed, and pthread_create() fails with the EBUSY error. 2. For the best performance during thread creation, you should always use pthread_join() or pthread_detach(). This allows resources to be reclaimed or reused when the thread terminates. 3. The OS/400 implementation of threads allows the user ID to be changed on a per-thread basis. If, at the time the application creates the first thread, the application has not associated a process user identity with the job, the system uses the identity of the current user to set the process user identity for the job. The process user identity is used by some operating system support when operations that require authorization checks are done against a multithreaded job from outside that job. The application can set the process user identity using the Set Job User Identify (QWTSJUID) or QwtSetJuid() Set Job User Identity APIs. See the Security APIs for more details.
Parameters
thread (Output) Pthread handle to the created thread attr (Input) The thread attributes object containing the attributes to be associated with the newly created thread. If NULL, the default thread attributes are used. start_routine (Input) The function to be run as the new threads start routine arg (Input) An address for the argument for the threads start routine
Return Value
0 pthread_create() was successful. value pthread_create() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_create() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EAGAIN] The system did not have enough resources to create another thread or the maximum number of threads for this job has been reached [EBUSY] The system cannot allow thread creation in this process at this time.
pthread_create()--Create Thread
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_exit()--Terminate Calling Thread pthread_cancel()--Cancel Thread pthread_detach()--Detach Thread pthread_join()--Wait for and Detach Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" typedef struct { int value; char string[128]; } thread_parm_t; void *threadfunc(void *parm) { thread_parm_t *p = (thread_parm_t *)parm; printf("%s, parm = %d\n", p->string, p->value); free(p); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; pthread_attr_t pta; thread_parm_t *parm=NULL; printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread attributes object\n"); rc = pthread_attr_init(&pta); checkResults("pthread_attr_init()\n", rc); /* Create 2 threads using default attributes in different ways */ printf("Create thread using the NULL attributes\n"); /* Set up multiple parameters to pass to the thread */ parm = malloc(sizeof(thread_parm_t)); parm->value = 5; strcpy(parm->string, "Inside secondary thread"); rc = pthread_create(&thread, NULL, threadfunc, (void *)parm); checkResults("pthread_create(NULL)\n", rc); printf("Create thread using the default attributes\n"); /* Set up multiple parameters to pass to the thread */ parm = malloc(sizeof(thread_parm_t)); parm->value = 77; strcpy(parm->string, "Inside secondary thread"); rc = pthread_create(&thread, &pta, threadfunc, (void *)parm);
pthread_create()--Create Thread
checkResults("pthread_create(&pta)\n", rc); printf("Destroy thread attributes object\n"); rc = pthread_attr_destroy(&pta); checkResults("pthread_attr_destroy()\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(5); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPCRT0 Create a thread attributes object Create thread using the NULL attributes Create thread using the default attributes Destroy thread attributes object Inside secondary thread, parm = 77 Inside secondary thread, parm = 5 Main completed
Parameters
interval (Input) Address of the timespec structure containing the interval to wait
Return Value
0 pthread_delay_np() was successful. value pthread_delay_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_delay_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q
The <pthread.h> header file. See Header files for Pthread functions.
Example
#define _MULTI_THREADED #include <stdio.h> #include <qp0z1170.h> #include <time.h> #include <pthread.h> #include "check.h" #define NTHREADS void *threadfunc(void *parm) { int rc; struct timespec ts = {0, 0}; /* 5 and 1/2 seconds */ ts.tv_sec = 5; ts.tv_nsec = 500000000; printf("Thread blocked\n"); rc = pthread_delay_np(&ts); if (rc != 0) { printf("pthread_delay_np() - return code %d\n", rc); return (void*)&rc; } printf("Wait timed out!\n"); return NULL; } int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid[NTHREADS]; void *status; int fail=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create %d threads\n", NTHREADS); for(i=0; i<NTHREADS; ++i) { rc = pthread_create(&threadid[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } printf("Wait for threads and cleanup\n"); for (i=0; i<NTHREADS; ++i) { rc = pthread_join(threadid[i], &status); checkResults("pthread_join()\n", rc); if (status != NULL) { fail = 1; } } 5
if (fail) { printf("At least one thread failed!\n"); exit(1); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPDLY0 Create 5 threads Thread blocked Thread blocked Thread blocked Thread blocked Wait for threads and cleanup Thread blocked Wait timed out! Wait timed out! Wait timed out! Wait timed out! Wait timed out! Main completed
pthread_detach()--Detach Thread
pthread_detach()--Detach Thread
Syntax #include <pthread.h> int pthread_detach(pthread_t thread); Threadsafe: Yes Signal Safe: No The pthread_detach() function indicates that system resources for the specified thread should be reclaimed when the thread ends. If the thread is already ended, resources are reclaimed immediately. This routine does not cause the thread to end. After pthread_detach() has been issued, it is not valid to try to pthread_join() with the target thread. Eventually, you should call pthread_join() or pthread_detach() for every thread that is created joinable (with a detach state of PTHREAD_CREATE_JOINABLE) so that the system can reclaim all resources associated with the thread. Failure to join to or detach threads that can be joined causes memory and other resource leaks until the process ends. If thread does not represent a valid undetached thread, pthread_detach() will return ESRCH.
Parameters
thread (Input) Pthread handle to the target thread
Return Value
0 pthread_detach() was successful. value pthread_detach() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_detach() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ESRCH] No item could be found that matches the specified value
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_exit()--Terminate Calling Thread pthread_create()--Create Thread pthread_join()--Wait for and Detach Thread
pthread_detach()--Detach Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include "check.h" void *threadfunc(void *parm) { printf("Inside secondary thread\n"); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create thread using attributes that allow join or detach\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); sleep(5); printf("Detach the thread after it terminates\n"); rc = pthread_detach(thread); checkResults("pthread_detach()\n", rc); printf("Detach the thread again (expect ESRCH)\n"); rc = pthread_detach(thread); if (rc != ESRCH) { printf("Got an unexpected result! rc=%d\n", rc); exit(1); } printf("Second detach fails correctly\n"); /* sleep() is not a very robust way to wait for the thread */ sleep(5); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPDET0 Create thread using attributes that allow join or detach Inside secondary thread Detach the thread after it terminates Detach the thread again (expect ESRCH) Second detach fails correctly Main completed
Parameters
t1 (Input) Pthread handle for thread 1 t2 (Input) Pthread handle for thread 2
Return Value
0 The Pthread handles do not refer to the same thread. 1 The Pthread handles refer to the same thread.
Error Conditions
None.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_self()--Get Pthread Handle pthread_create()--Create Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_t theThread;
theThread = pthread_self(); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create thread using default attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(5); printf("Check if global vs local pthread_t are equal\n"); if (!pthread_equal(thread, theThread)) { printf("Unexpected results on pthread_equal()!\n"); exit(1); } printf("pthread_equal returns true\n"); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPEQU0 Create thread using default attributes Inside secondary thread Check if global vs local pthread_t are equal pthread_equal returns true Main completed
exception. This indicates that the thread is already considered terminated by the system, and pthread_exit() cannot continue. If your code does not handle this exception, it will appear as if the call to pthread_exit() was successful.
Parameters
status (Input) exit status of the thread
Return Value
pthread_exit() does not return.
Error Conditions
None.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread pthread_create()--Create Thread pthread_join()--Wait for and Detach Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" int theStatus=5;
void *threadfunc(void *parm) { printf("Inside secondary thread\n"); pthread_exit(__VOID(theStatus)); return __VOID(theStatus); /* Not needed, but this makes the compiler smile */ } int main(int argc, char **argv) { pthread_t thread; int rc=0; void *status; printf("Enter Testcase - %s\n", argv[0]); printf("Create thread using attributes that allow join\n");
rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Wait for the thread to exit\n"); rc = pthread_join(thread, &status); checkResults("pthread_join()\n", rc); if (__INT(status) != theStatus) { printf("Secondary thread failed\n"); exit(1); } printf("Got secondary thread status as expected\n"); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPEXIT0 Create thread using attributes that allow join Wait for the thread to exit Inside secondary thread Got secondary thread status as expected Main completed
Parameters
thread (Input) Pthread handle to the target thread status (Input/Output) Address of the variable to receive the thread's exit status options (Input) Address of the join options structure specifying optional behavior of this API.
Return Value
0 pthread_extendedjoin_np() was successful. value pthread_extendedjoin_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_extendedjoin_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ESRCH] The thread specified could not be found. [ETIMEDOUT] The time specified in the deltatime field of the options parameter elapsed without the target thread terminating.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_detach()--Detach Thread pthread_exit()--Terminate Calling Thread pthread_join()--Wait for and Detach Thread pthread_join_np()--Wait for Thread to End
Example
#define _MULTI_THREADED #include <pthread.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <stdio.h> #include "check.h" static void *thread(void *parm) { printf("Entered thread\n"); sleep(10); printf("Ending thread\n"); return __VOID(42); } int main (int argc, char *argv[])
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_19.htm (2 of 3) [2/9/2001 1:56:36 PM]
printf("Entering testcase %s\n", argv[0]); printf("Create thread using attributes that allow join\n"); rc = pthread_create(&t, NULL, thread, NULL); checkResults("pthread_create()\n", rc); memset(&joinoption, 0, sizeof(pthread_joinoption_np_t)); joinoption.deltatime.tv_sec = 3; joinoption.leaveThreadAllocated = 1; printf("Join to the thread, timeout in 3 seconds, no implicit detach\n"); rc = pthread_extendedjoin_np(t, &status, &joinoption); if (rc != ETIMEDOUT) { printf("Join did not timeout as expected! rc=%d\n", rc); exit(1); } /* Call pthread_extendedjoin_np the same as a normal /* pthread_join() call. /* i.e. Implicit Detach is done, and Infinite wait printf("Normal join to the thread\n"); rc = pthread_extendedjoin_np(t, &status, NULL); checkResults("pthread_extendedjoin_np(no-options)\n", rc); if (__INT(status) != 42) { printf("Got the incorrect thread status!\n"); exit(1); } printf("Main completed\n"); return(0); } */ */ */
Output
Entering testcase QP0WTEST/TPJOINE0 Create thread using attributes that allow join Join to the thread, timeout in 3 seconds, no implicit detach Entered thread Normal join to the thread Ending thread Main completed
Parameters
None.
Return Value
value pthread_getconcurrency() returns the current concurrency level.
Error Conditions
None.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_setconcurrency()--Set Process Concurrency Level
Parameters
option (Input/Output) Address of the variable containing option information and to contain output option information.
Return Value
0 pthread_getpthreadoption_np() was successful. value pthread_getpthreadoption_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_getpthreadoption_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_setpthreadoption_np()--Set Pthread Run-Time Option Data
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void *threadfunc(void *parm) { printf("Inside the thread\n"); return NULL; } void showCurrentSizeOfPool(void) { int rc; pthread_option_np_t opt; memset(&opt, 0, sizeof(opt)); opt.option = PTHREAD_OPTION_POOL_CURRENT_NP; rc = pthread_getpthreadoption_np(&opt); checkResults("pthread_getpthreadoption_np()\n", rc);
printf("Current number of thread structures in pool is %d\n", opt.optionValue); return; } int main(int argc, char **argv) { pthread_t int pthread_option_np_t thread; rc=0; opt;
printf("Enter Testcase - %s\n", argv[0]); printf("Create thread using the NULL attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); memset(&opt, 0, sizeof(opt)); opt.option = PTHREAD_OPTION_POOL_NP; rc = pthread_getpthreadoption_np(&opt); checkResults("pthread_getpthreadoption_np()\n", rc); printf("Current maximum pool size is %d thread structures\n", opt.optionValue); showCurrentSizeOfPool(); printf("Joining to the thread may it to the storage pool\n"); rc = pthread_join(thread, NULL); checkResults("pthread_join()\n", rc); showCurrentSizeOfPool(); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPGETOPT Create thread using the NULL attributes Current maximum pool size is 512 thread structures Current number of thread structures in pool is 0 Joining to the thread may it to the storage pool Inside the thread Current number of thread structures in pool is 1 Main completed
Parameters
thread (Input) Pthread handle representing the target thread policy (Output) Address of the variable to contain the scheduling policy param (Output) Address of the variable to contain the scheduling parameters
Return Value
0 pthread_getschedparam() was successful. value pthread_getschedparam was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_getschedparam() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_setschedparam()--Set Target Thread Scheduling Parameters
Example
#define _MULTI_THREADED #include <pthread.h> #include <sched.h> #include <stdio.h> #include "check.h" void *threadfunc(void *parm) { printf("Inside secondary thread\n"); sleep(5); /* Sleep is not a very robust way to serialize threads */ return NULL; } int main(int argc, char { pthread_t int struct sched_param int **argv) thread; rc=0; param; policy;
printf("Enter Testcase - %s\n", argv[0]); printf("Create thread using default attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Get scheduling parameters\n"); rc = pthread_getschedparam(thread, &policy, ¶m); checkResults("pthread_getschedparam()\n", rc); printf("The thread scheduling parameters indicate:\n" "policy = %d\n", policy); printf("priority = %d\n", param.sched_priority); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPGSP0 Create thread using default attributes Get scheduling parameters The thread scheduling parameters indicate: policy = 0 priority = 0 Main completed
Parameters
None.
Return Value
The pthread_id_np_t structure identifying the thread
Error Conditions
None.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_self()--Get Pthread Handle pthread_getunique_np()--Retrieve Unique ID for Target Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" #define NUMTHREADS 3
void *threadfunc(void *parm) { printf("Thread 0x%.8x %.8x started\n", pthread_getthreadid_np()); return NULL; } int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; pthread_id_np_t tid; int i=0; printf("Enter Testcase - %s\n", argv[0]); printf("Main Thread 0x%.8x %.8x\n", pthread_getthreadid_np()); printf("Create %d threads using joinable attributes\n", NUMTHREADS); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&thread[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); pthread_getunique_np(&thread[i], &tid); printf("Created thread 0x%.8x %.8x\n", tid); } printf("Join to threads\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPGETT0 Main Thread 0x00000000 0000006c Create 3 threads using joinable attributes Created thread 0x00000000 0000006d Thread 0x00000000 0000006d started Created thread 0x00000000 0000006e Created thread 0x00000000 0000006f Join to threads Thread 0x00000000 0000006f started Thread 0x00000000 0000006e started Main completed
Parameters
thread (Input) Thread to retrieve the unique integer ID for id (Output) Address of the thread ID structure to contain the 64-bit thread ID.
Return Value
0 pthread_getunique_np() was successful.
value pthread_getunique_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_getunique_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions pthread_self()--Get Pthread Handle pthread_getthreadid_np()--Retrieve Unique ID for Calling Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" #define NUMTHREADS 3
void *threadfunc(void *parm) { pthread_id_np_t tid; pthread_t me = pthread_self(); pthread_getunique_np(&me, &tid); printf("Thread 0x%.8x %.8x started\n", tid); return NULL; } int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; pthread_id_np_t tid; int i=0; pthread_t me = pthread_self(); printf("Enter Testcase - %s\n", argv[0]); pthread_getunique_np(&me, &tid); printf("Main Thread 0x%.8x %.8x\n", tid); printf("Create %d threads using joinable attributes\n", NUMTHREADS); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&thread[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); pthread_getunique_np(&thread[i], &tid); printf("Created thread 0x%.8x %.8x\n", tid); }
printf("Join to threads\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPGETU0 Main Thread 0x00000000 0000006c Create 3 threads using joinable attributes Created thread 0x00000000 0000006d Thread 0x00000000 0000006d started Created thread 0x00000000 0000006e Created thread 0x00000000 0000006f Join to threads Thread 0x00000000 0000006f started Thread 0x00000000 0000006e started Main completed
Parameters
None.
Return Value
0 The calling thread is a secondary thread. value The calling thread is the initial thread.
Error Conditions
None.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_is_multithreaded_np()--Check the Current Number of Threads
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" #define NUMTHREADS 1
printf("Inside the function\n"); if (pthread_is_initialthread_np()) { printf("In the initial thread\n"); } else { printf("In a secondary thread\n"); } return NULL; } int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; int i=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create %d threads\n", NUMTHREADS);
for (i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&thread[i], NULL, function, NULL); checkResults("pthread_create()\n", rc); printf("Main: Currently %d threads\n", pthread_is_initialthread_np() + 1); } printf("Join to threads\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); } function(NULL); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPISIN0 Create 1 threads Join to threads Inside the function In a secondary thread Inside the function In the initial thread Main completed
Parameters
None.
Return Value
0 No other threads exist in the process. value There are currently value+1 total threads in the process.
Error Conditions
None.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_is_initialthread_np()--Check if Running in the Initial Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h"
#define
NUMTHREADS
void *threadfunc(void *parm) { int myHiId; int myId; pthread_t me = pthread_self(); printf("Inside the New Thread\n"); sleep(2); /* Sleep is not a very robust way to serialize threads */ return NULL; } int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; int theHiId=0; int theId=0; int i=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create %d threads\n", NUMTHREADS);
for (i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&thread[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Main: Currently %d threads\n", pthread_is_multithreaded_np() + 1); } printf("Join to threads\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); } if (rc = pthread_is_multithreaded_np()) { printf("Error: %d Threads still exist!\n", rc+1); exit(1); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPISMT0 Create 3 threads Main: Currently 2 threads Main: Currently 3 threads Main: Currently 4 threads Join to threads Inside the New Thread Inside the New Thread Inside the New Thread Main completed
Parameters
thread (Input) Pthread handle to the target thread status (Output) Address of the variable to receive the thread's exit status
Return Value
0 pthread_join() was successful. value pthread_join() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_join() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ESRCH] The thread specified could not be found.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_detach()--Detach Thread pthread_exit()--Terminate Calling Thread pthread_extendedjoin_np()--Wait for Thread with Extended Options pthread_join_np()--Wait for Thread to End
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" int okStatus = 34;
void *threadfunc(void *parm) { printf("Inside secondary thread\n"); return __VOID(okStatus); } int main(int argc, char **argv) { pthread_t thread; int rc=0; void *status; printf("Enter Testcase - %s\n", argv[0]); printf("Create thread using attributes that allow join\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Wait for the thread to exit\n"); rc = pthread_join(thread, &status); checkResults("pthread_join()\n", rc); if (__INT(status) != okStatus) { printf("Secondary thread failed\n"); exit(1); } printf("Got secondary thread status as expected\n"); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPJOIN0 Create thread using attributes that allow join Wait for the thread to exit Inside secondary thread Got secondary thread status as expected Main completed
Parameters
thread (Input) Pthread handle to the target thread status (Output) Address of the variable to receive the thread's exit status
Return Value
0 pthread_join_np() was successful. value pthread_join_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_join_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_detach()--Detach Thread pthread_exit()--Terminate Calling Thread pthread_extendedjoin_np()--Wait for Thread with Extended Options pthread_join()--Wait for and Detach Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" int okStatus = 12;
void *threadfunc(void *parm) { printf("Inside secondary thread\n"); return __VOID(okStatus); } int main(int argc, char **argv) { pthread_t thread; int rc=0; void *status; printf("Enter Testcase - %s\n", argv[0]); printf("Create thread using attributes that allow join\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Wait for the thread to exit\n"); rc = pthread_join_np(thread, &status); checkResults("pthread_join_np()\n", rc); if (__INT(status) != okStatus) { printf("Secondary thread failed\n"); exit(1); } printf("With pthread_join_np(), we can join repeatedly\n"); rc = pthread_join_np(thread, &status); checkResults("pthread_join_np()\n", rc); if (__INT(status) != okStatus) { printf("Secondary thread failed\n"); exit(1); } printf("Got secondary thread status as expected\n"); /* Eventually, we should use pthread_join() or pthread_detach() */
Output:
Enter Testcase - QP0WTEST/TPJOINN0 Create thread using attributes that allow join Wait for the thread to exit Inside secondary thread With pthread_join_np(), we can join repeatedly Got secondary thread status as expected Main completed
Parameters
once_control (Input) The control variable associated with this initialization. init_routine (Input) A function pointer to a routine that takes no parameters and returns no value.
Return Value
0 pthread_once() was successful. value pthread_once() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_once() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q
The <pthread.h> header file. See Header files for Pthread functions.
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" #define int int pthread_once_t NUMTHREADS 3 number = 0; okStatus = 777; onceControl = PTHREAD_ONCE_INIT;
void initRoutine(void) { printf("In the initRoutine\n"); number++; } void *threadfunc(void *parm) { printf("Inside secondary thread\n"); pthread_once(&onceControl, initRoutine); return __VOID(okStatus); } int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; int i=NUMTHREADS; void *status; printf("Enter Testcase - %s\n", argv[0]); for (i=0; i < NUMTHREADS; ++i) { printf("Create thread %d\n", i); rc = pthread_create(&thread[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } for (i=0; i < NUMTHREADS; ++i) { printf("Wait for thread %d\n", i); rc = pthread_join(thread[i], &status); checkResults("pthread_join()\n", rc); if (__INT(status) != okStatus) { printf("Secondary thread failed\n"); exit(1); } } if (number != 1) { printf("An incorrect number of 1 one-time init routine was called!\n"); exit(1); } printf("One-time init routine called exactly once\n"); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPONCE0 Create thread 0 Create thread 1 Create thread 2 Wait for thread 0 Inside secondary thread In the initRoutine Inside secondary thread Wait for thread 1 Wait for thread 2 Inside secondary thread One-time init routine called exactly once Main completed
Parameters
None.
Return Value
pthread_t pthread_self() returns the Pthread handle of the calling thread.
Error Conditions
None.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_equal()--Compare Two Threads pthread_getthreadid_np()--Retrieve Unique ID for Calling Thread pthread_getunique_np()--Retrieve Unique ID for Target Thread
Example
#include #include #include #include pthread_t <pthread.h> <pthread.h> <stdio.h> "check.h" theThread;
void *threadfunc(void *parm) { printf("Inside secondary thread\n"); theThread = pthread_self(); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; printf("Entering testcase\n"); printf("Create thread using default attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(5); printf("Check if the thread got its thread handle\n"); if (!pthread_equal(thread, theThread)) { printf("Unexpected results on pthread_equal()!\n"); exit(1); } printf("pthread_self() returned the thread handle\n"); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create thread using default attributes Inside secondary thread Check if the thread got its thread handle pthread_self() returned the thread handle Main completed
Parameters
concurrency (Input) The new concurrency level for the process
Return Value
0 pthread_setconcurrency() was successful. value pthread_setconcurrency() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_setconcurrency() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_getconcurrency()--Get Process Concurrency Level
Parameters
option (Input/Output) Address of the variable containing option information and to contain output option information
Return Value
0 pthread_getpthreadoption_np() was successful.
value pthread_getpthreadoption_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_getpthreadoption_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_getpthreadoption_np()--Get Pthread Run-Time Option Data
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" #define NUMTHREADS 5
void *threadfunc(void *parm) { printf("Inside the thread\n"); return NULL; } void showCurrentSizeOfPool(void) { int rc; pthread_option_np_t opt; memset(&opt, 0, sizeof(opt)); opt.option = PTHREAD_OPTION_POOL_CURRENT_NP; rc = pthread_getpthreadoption_np(&opt); checkResults("pthread_getpthreadoption_np()\n", rc); printf("Current number of thread structures in pool is %d\n", opt.optionValue); return; } int main(int argc, char { pthread_t int int pthread_option_np_t **argv) thread[NUMTHREADS]; rc=0; i=0; opt;
printf("Enter Testcase - %s\n", argv[0]); printf("Create threads and prime the storage pool\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&thread[i], NULL, threadfunc, NULL);
checkResults("pthread_create(NULL)\n", rc); } printf("Joining all threads at once so thread n does not reuse\n" "thread n-1's data structures\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); } showCurrentSizeOfPool(); /* Set the maximum size of the storage pool to 0. I.e. No reuse of /* pthread structures printf("Set the max size of the storage pool to 0\n"); memset(&opt, 0, sizeof(opt)); opt.option = PTHREAD_OPTION_POOL_NP; opt.optionValue = 0; rc = pthread_setpthreadoption_np(&opt); checkResults("pthread_setpthreadoption_np()\n", rc); */ */
printf("Create some more threads. Each thread structure will come\n" "from the storage pool if it exists, but based on the max size of 0,\n" "the thread structure will not be allowed to be reused\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&thread[i], NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); showCurrentSizeOfPool(); rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); }
Output:
Enter Testcase - QP0WTEST/TPSETOPT Create threads and prime the storage pool Joining all threads at once so thread n does not reuse thread n-1's data structures Inside the thread Inside the thread Inside the thread Inside the thread Inside the thread Current number of thread structures in pool is 5 Set the max size of the storage pool to 0 Create some more threads. Each thread structure will come from the storage pool if it exists, but based on the max size of 0, the thread structure will not be allowed to be reused Current number of thread structures in pool is 4 Inside the thread
Current number of Inside the thread Current number of Inside the thread Current number of Inside the thread Current number of Inside the thread Main completed
thread structures in pool is 3 thread structures in pool is 2 thread structures in pool is 1 thread structures in pool is 0
Parameters
thread (Input) Pthread handle of the target thread policy (Input) Scheduling policy (must be SCHED_OTHER) param (Input) Scheduling parameters
Return Value
0 pthread_setschedparam() was successful. value pthread_setschedparam() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_setschedparam() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ENOTSUP]
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_getschedparam()--Get Thread Scheduling Parameters
Example
#define _MULTI_THREADED #include <pthread.h> #include <sched.h> #include <stdio.h> #include "check.h" #define int BUMP_PRIO 1 thePriority = 0;
int showSchedParam(pthread_t thread) { struct sched_param param; int policy; int rc; printf("Get scheduling parameters\n"); rc = pthread_getschedparam(thread, &policy, ¶m); checkResults("pthread_getschedparam()\n", rc); printf("The thread scheduling parameters indicate:\n" "priority = %d\n", param.sched_priority); return param.sched_priority; } void *threadfunc(void *parm) { int rc; printf("Inside secondary thread\n"); thePriority = showSchedParam(pthread_self()); sleep(5); /* Sleep is not a very robust way to serialize threads */ return NULL; } int main(int argc, char { pthread_t int struct sched_param int int **argv) thread; rc=0; param; policy = SCHED_OTHER; theChangedPriority=0;
printf("Enter Testcase - %s\n", argv[0]); printf("Create thread using default attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); sleep(2); /* Sleep is not a very robust way to serialize threads */
memset(¶m, 0, sizeof(param)); /* Bump the priority of the thread a small amount */ if (thePriority - BUMP_PRIO >= PRIORITY_MIN_NP) { param.sched_priority = thePriority - BUMP_PRIO; } printf("Set scheduling parameters, prio=%d\n", param.sched_priority); rc = pthread_setschedparam(thread, policy, ¶m); checkResults("pthread_setschedparam()\n", rc); /* Let the thread fill in its own last priority */ theChangedPriority = showSchedParam(thread); if (thePriority == theChangedPriority || param.sched_priority != theChangedPriority) { printf("The thread did not get priority set correctly, " "first=%d last=%d expected=%d\n", thePriority, theChangedPriority, param.sched_priority); exit(1); } sleep(5); /* Sleep is not a very robust way to serialize threads */ printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPSSP0 Create thread using default attributes Inside secondary thread Get scheduling parameters The thread scheduling parameters indicate: priority = 0 Set scheduling parameters, prio=-1 Get scheduling parameters The thread scheduling parameters indicate: priority = -1 Main completed
PTHREAD_TRACE_NONE_NP
PTHREAD_TRACE_ERROR_NP
PTHREAD_TRACE_INFO_NP
PTHREAD_TRACE_VERBOSE_NP "QIBM_PTHREAD_TRACE_LEVEL=3"
Verbose level traces informational level tracepoints, plus detailed information about application parameters, threads and data structures including information about Pthreads library processing information.
The application provides tracing support similar to the Pthreads library using the PTHREAD_TRACE_NP() macro. The PTHREAD_TRACE_NP() macro uses the external variable Qp0wTraceLevel. Qp0wTraceLevel may be used directly by the application to set application trace level without effecting the current Pthread library trace level. Set the value of Qp0wTraceLevel to one of PTHREAD_TRACE_NONE_NP, PTHREAD_TRACE_ERROR_NP, PTHREAD_TRACE_INFO_NP, or PTHREAD_TRACE_VERBOSE_NP. The PTHREAD_TRACE_NP() macro can be used in conjunction with the following APIs to put trace records into the user trace flight recorder. The following system APIs defined in the qp0ztrc.h header file:
q q q q
Qp0zUprintf - print formatted trace data Qp0zDump - dump formatted hex data Qp0zDumpStack - dump the call stack of the calling thread Qp0zDumpTargetStack - dump the call stack of the target thread
The trace records are written to the user trace flight recorder and can be accessed via the following CL commands:
q q q
DMPUSRTRC - dump the contents of a specified job's trace CHGUSRTRC - change attributes (size, wrapping, clear) of a specified job's trace DLTUSRTRC - delete the persistent trace object associated with a job's trace
Parameters
None.
Return Value
value The new trace level. One of PTHREAD_TRACE_NONE_NP, PTHREAD_TRACE_ERROR_NP, PTHREAD_TRACE_INFO_NP, or PTHREAD_TRACE_VERBOSE_NP.
Error Conditions
None.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. PTHREAD_TRACE_NP()--Execute code based on trace level (Macro)
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <qp0ztrc.h> #define checkResults(string, val) { \ if (val) { \ printf("Failed with %d at %s", val, string); \ exit(1); \ } \ } typedef struct { int threadSpecific1; int threadSpecific2; } threadSpecific_data_t; #define pthread_key_t NUMTHREADS 2 threadSpecificKey;
void foo(void); void bar(void); void dataDestructor(void *); void *theThread(void *parm) { int rc; threadSpecific_data_t *gData; PTHREAD_TRACE_NP({ Qp0zUprintf("Thread Entered\n"); Qp0zDump("Global Data", parm, sizeof(threadSpecific_data_t));}, PTHREAD_TRACE_INFO_NP); gData = (threadSpecific_data_t *)parm; rc = pthread_setspecific(threadSpecificKey, gData); checkResults("pthread_setspecific()\n", rc); foo(); return NULL; } void foo() { threadSpecific_data_t *gData = (threadSpecific_data_t *)pthread_getspecific(threadSpecificKey); PTHREAD_TRACE_NP(Qp0zUprintf("foo(), threadSpecific data=%d %d\n", gData->threadSpecific1,
gData->threadSpecific2);, PTHREAD_TRACE_INFO_NP); bar(); PTHREAD_TRACE_NP(Qp0zUprintf("foo(): This is an error tracepoint\n");, PTHREAD_TRACE_ERROR_NP); } void bar() { threadSpecific_data_t *gData = (threadSpecific_data_t *)pthread_getspecific(threadSpecificKey); PTHREAD_TRACE_NP(Qp0zUprintf("bar(), threadSpecific data=%d %d\n", gData->threadSpecific1, gData->threadSpecific2);, PTHREAD_TRACE_INFO_NP); PTHREAD_TRACE_NP(Qp0zUprintf("bar(): This is an error tracepoint\n"); Qp0zDumpStack("This thread's stack at time of error in bar()");, PTHREAD_TRACE_ERROR_NP); return; } void dataDestructor(void *data) { PTHREAD_TRACE_NP(Qp0zUprintf("dataDestructor: Free data\n");, PTHREAD_TRACE_INFO_NP); pthread_setspecific(threadSpecificKey, NULL); free(data); /* If doing verbose tracing we'll even write a message to the job log */ PTHREAD_TRACE_NP(Qp0zLprintf("Free'd the thread specific data\n");, PTHREAD_TRACE_VERBOSE_NP); } /* Call this testcase with an optional parameter 'PTHREAD_TRACING' */ /* If the PTHREAD_TRACING parameter is specified, then the */ /* Pthread tracing environment variable will be set, and the */ /* pthread tracing will be re initialized from its previous value. */ /* NOTE: We set the trace level to informational, tracepoints cut */ /* using PTHREAD_TRACE_NP at a VERBOSE level will NOT show up*/ int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; int i; threadSpecific_data_t *gData; char buffer[50]; PTHREAD_TRACE_NP(Qp0zUprintf("Enter Testcase - %s\n", argv[0]);, PTHREAD_TRACE_INFO_NP); if (argc == 2 && !strcmp("PTHREAD_TRACING", argv[1])) { /* Turn on internal pthread function tracing support */ /* Or, use ADDENVVAR, CHGENVVAR CL commands to set this envvar*/ sprintf(buffer, "QIBM_PTHREAD_TRACE_LEVEL=%d", PTHREAD_TRACE_INFO_NP); putenv(buffer); /* Refresh the Pthreads internal tracing with the environment */ /* variables value. */ pthread_trace_init_np(); } else { /* Trace only our application, not the Pthread code */ Qp0wTraceLevel = PTHREAD_TRACE_INFO_NP; } rc = pthread_key_create(&threadSpecificKey, dataDestructor); checkResults("pthread_key_create()\n", rc);
for (i=0; i <NUMTHREADS; ++i) { PTHREAD_TRACE_NP(Qp0zUprintf("Create/start a thread\n");, PTHREAD_TRACE_INFO_NP); /* Create per-thread threadSpecific data and pass it to the thread */ gData = (threadSpecific_data_t *)malloc(sizeof (threadSpecific_data_t)); gData->threadSpecific1 = i; gData->threadSpecific2 = (i+1)*2; rc = pthread_create( &thread[i], NULL, theThread, gData); checkResults("pthread_create()\n", rc); PTHREAD_TRACE_NP(Qp0zUprintf("Wait for the thread to complete, " "and release their resources\n");, PTHREAD_TRACE_INFO_NP); rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); } pthread_key_delete(threadSpecificKey); PTHREAD_TRACE_NP(Qp0zUprintf("Main completed\n");, PTHREAD_TRACE_INFO_NP); return 0; } Output Use CL command DMPUSRTRC to output the following tracing information that the example creates. The DMPUSRTRC CL command causes the following information to be put into file QTEMP/QAP0ZDMP or to standard output depending on the options used for the CL command. Note the following:
q
The trace records are indented and labeled based on thread id plus a microsecond timestamp at the time the tracepoint was cut. In the following trace record, the value 00000018 indicates the thread ID of the thread that created the tracepoint. The value 972456 indicates that the tracepoint occurred 972456 microseconds after the last timestamp indicator. 00000018:972456 pthread_trace_init_np(): New traceLevel=2
You can use the Pthread library tracepoints to debug incorrect calls to the Pthreads library from your application. The following trace output occurs when the optional parameter 'PTHREAD_TRACING' IS specified when calling this program. The 'PTHREAD_TRACING' parameter causes the pthread_trace_init_np()() function to be used which initializes the Pthreads library tracing. There is significantly more information traced than the example shown in the documentation for the PTHREAD_TRACE_NP() macro The function names for threads and data destructors are traced. The values for many Pthread API parameters are traced, allowing application debug. Some internal Pthread API information is traced at an information-level tracing when the control flow information is critical.
q q q
User Trace Dump for job 097979/KULACK/PTHREADT. Size: 300K, Wrapped 0 times. --- 11/09/1998 15:15:56 --00000018:972456 pthread_trace_init_np(): New traceLevel=2 00000018:972592 pthread_key_create(entry): dtor=a1000000 00000000 d161cc19 45001a00 00000018:993920 destructor name is 'dataDestructor__FPv' 00000018:994048 pthread_key_create(exit): newKey=0, rc=0 00000018:994120 Create/start a thread
00000018:994224 pthread_create(entry): thread=80000000 00000000 f11d9cc7 23000400 00000018:994296 attr=00000000 00000000 00000000 00000000 00000018:994376 start_routine=a1000000 00000000 d161cc19 45006980 00000018:995320 routine name is 'theThread__FPv' 00000018:995432 arg=80000000 00000000 e7c74b3e 04001cd0 00000018:995992 pthread_create(status): Create a new thread 00000018:996088 Joinable-1 00000018:996152 PrioInheritSched-EXPLICIT Prio-0 00000018:997488 pthread_create(exit): Success 00000018:997632 tcb=80000000 00000000 feb52907 07001000 00000018:997704 thread id=00000000 00000019 handle=00000007 00000018:997792 Wait for the thread to complete, and release their resources 00000018:997896 pthread_join_processor(entry): Target 00000000 00000019, Detach=1, time=00000000 sec, 00000000 nanosec. 00000018:997968 statusp = 00000000 00000000 00000000 00000000 00000019:998720 pthread_create_part2(status): run the new thread: 00000000 00000019 00000019:998864 Thread Entered 00000019:998984 E7C74B3E04:001CD0 L:0008 Global Data 00000019:999144 E7C74B3E04:001CD0 00000000 00000002 *................* 00000019:999240 pthread_setspecific(entry): value=80000000 00000000 e7c74b3e 04001cd0, key=0 00000019:999320 pthread_getspecific(entry): key=0 00000019:999392 foo(), threadSpecific data=0 2 00000019:999464 pthread_getspecific(entry): key=0 00000019:999536 bar(), threadSpecific data=0 2 00000019:999600 bar(): This is an error tracepoint 00000019:999664 Stack Dump For Current Thread 00000019:999728 Stack: This thread's stack at time of error in bar() --- 11/09/1998 15:15:57 --00000019:000304 Stack: Library / Program Module Stmt Procedure 00000019:000472 Stack: QSYS / QLESPI QLECRTTH 774 : LE_Create_Thread2__FP12crtth_parm_t 00000019:000560 Stack: QSYS / QP0WPTHR QP0WPTHR 1008 : pthread_create_part2 00000019:000656 Stack: KULACK / PTHREADT PTHREADT 19 : theThread__FPv 00000019:000728 Stack: KULACK / PTHREADT PTHREADT 29 : foo__Fv 00000019:000808 Stack: KULACK / PTHREADT PTHREADT 46 : bar__Fv 00000019:000888 Stack: QSYS / QP0ZCPA QP0ZUDBG 87 : Qp0zDumpStack 00000019:007416 Stack: QSYS / QP0ZSCPA QP0ZSCPA 276 : Qp0zSUDumpStack 00000019:007504 Stack: QSYS / QP0ZSCPA QP0ZSCPA 287 : Qp0zSUDumpTargetStack 00000019:007544 Stack: Completed 00000019:007664 foo(): This is an error tracepoint 00000019:007752 pthread_create_part2(status): return from start routine, status=00000000 00000000 00000000 00000000
00000019:007816 pthread_cleanup(entry): Thread termination started 00000019:007888 Qp0wTlsVector::invokeHandlers(entry): 00000019:007952 Qp0wTlsVector::invokeHandler(invoke): key=0 00000019:008040 dtor=a1000000 00000000 d161cc19 45001a00, 00000019:010792 destructor name is 'dataDestructor__FPv' 00000019:010920 arg=80000000 00000000 e7c74b3e 04001cd0 00000019:011008 dataDestructor: Free data 00000019:011096 pthread_setspecific(entry): value=00000000 00000000 00000000 00000000, key=0 00000019:011184 pthread_cleanup(exit): returning 00000018:011624 pthread_join_processor(status): target status=00000000 00000000 00000000 00000000, state=0x03, YES 00000018:011752 Create/start a thread 00000018:011880 pthread_create(entry): thread=80000000 00000000 f11d9cc7 23000430 00000018:011952 attr=00000000 00000000 00000000 00000000 00000018:012032 start_routine=a1000000 00000000 d161cc19 45006980 00000018:013464 routine name is 'theThread__FPv' 00000018:013576 arg=80000000 00000000 e7c74b3e 04001cd0 00000018:013704 Qp0wTcb::Qp0wTcb(status): Tcb was reused: tcb=80000000 00000000 feb52907 07001000 00000018:013784 pthread_create(status): Create a new thread 00000018:013848 Joinable-1 00000018:013912 PrioInheritSched-EXPLICIT Prio-0 00000018:014736 pthread_create(exit): Success 00000018:014912 tcb=80000000 00000000 feb52907 07001000 00000018:014984 thread id=00000000 0000001a handle=00000007 00000018:015072 Wait for the thread to complete, and release their resources 00000018:015168 pthread_join_processor(entry): Target 00000000 0000001a, Detach=1, time=00000000 sec, 00000000 nanosec. 00000018:015240 statusp = 00000000 00000000 00000000 00000000 0000001A:015696 pthread_create_part2(status): run the new thread: 00000000 0000001a 0000001A:015840 Thread Entered 0000001A:015968 E7C74B3E04:001CD0 L:0008 Global Data 0000001A:016128 E7C74B3E04:001CD0 00000001 00000004 *................* 0000001A:016232 pthread_setspecific(entry): value=80000000 00000000 e7c74b3e 04001cd0, key=0 0000001A:016304 pthread_getspecific(entry): key=0 0000001A:016384 foo(), threadSpecific data=1 4 0000001A:016456 pthread_getspecific(entry): key=0 0000001A:016528 bar(), threadSpecific data=1 4 0000001A:016584 bar(): This is an error tracepoint 0000001A:016648 Stack Dump For Current Thread 0000001A:016712 Stack: This thread's stack at time of error in bar() 0000001A:016904 Stack: Library / Program Module Stmt Procedure 0000001A:017048 Stack: QSYS / QLESPI QLECRTTH 774 : LE_Create_Thread2__FP12crtth_parm_t 0000001A:017144 Stack: QSYS / QP0WPTHR QP0WPTHR 1008 :
pthread_create_part2 0000001A:017232 Stack: KULACK / PTHREADT PTHREADT 19 : theThread__FPv 0000001A:018680 Stack: KULACK / PTHREADT PTHREADT 29 : foo__Fv 0000001A:018760 Stack: KULACK / PTHREADT PTHREADT 46 : bar__Fv 0000001A:018840 Stack: QSYS / QP0ZCPA QP0ZUDBG 87 : Qp0zDumpStack 0000001A:018928 Stack: QSYS / QP0ZSCPA QP0ZSCPA 276 : Qp0zSUDumpStack 0000001A:019000 Stack: QSYS / QP0ZSCPA QP0ZSCPA 287 : Qp0zSUDumpTargetStack 0000001A:019040 Stack: Completed 0000001A:019136 foo(): This is an error tracepoint 0000001A:019224 pthread_create_part2(status): return from start routine, status=00000000 00000000 00000000 00000000 0000001A:019288 pthread_cleanup(entry): Thread termination started 0000001A:019352 Qp0wTlsVector::invokeHandlers(entry): 0000001A:019424 Qp0wTlsVector::invokeHandler(invoke): key=0 0000001A:019504 dtor=a1000000 00000000 d161cc19 45001a00, 0000001A:021360 destructor name is 'dataDestructor__FPv' 0000001A:021496 arg=80000000 00000000 e7c74b3e 04001cd0 0000001A:021576 dataDestructor: Free data 0000001A:021664 pthread_setspecific(entry): value=00000000 00000000 00000000 00000000, key=0 0000001A:021752 pthread_cleanup(exit): returning 00000018:022112 pthread_join_processor(status): target status=00000000 00000000 00000000 00000000, state=0x03, YES 00000018:022272 pthread_key_delete(entry): key=0 00000018:022336 pthread_key_delete(exit): rc=0 00000018:022408 Main completed
the user trace flight recorder. The following system APIs defined in the qp0ztrc.h header file:
q q q q
Qp0zUprintf - print formatted trace data Qp0zDump - dump formatted hex data Qp0zDumpStack - dump the call stack of the calling thread Qp0zDumpTargetStack - dump the call stack of the target thread
The trace records are written to the user trace flight recorder and can be accessed via the following CL commands
q q q
DMPUSRTRC - dump the contents of a specified job's trace CHGUSRTRC - change attributes (size, wrapping, clear) of a specified job's trace DLTUSRTRC - delete the persistent trace object associated with a job's trace
Parameters
None.
Return Value
None.
Error Conditions
None.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_trace_init_np()--Initialize or Re-initialize pthread tracing
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <qp0ztrc.h> #define checkResults(string, val) { \ if (val) { \ printf("Failed with %d at %s", val, string); \ exit(1); \ } \ } typedef struct { int threadSpecific1; int threadSpecific2;
void foo(void); void bar(void); void dataDestructor(void *); void *theThread(void *parm) { int rc; threadSpecific_data_t *gData; PTHREAD_TRACE_NP({ Qp0zUprintf("Thread Entered\n"); Qp0zDump("Global Data", parm, sizeof(threadSpecific_data_t));}, PTHREAD_TRACE_INFO_NP); gData = (threadSpecific_data_t *)parm; rc = pthread_setspecific(threadSpecificKey, gData); checkResults("pthread_setspecific()\n", rc); foo(); return NULL; } void foo() { threadSpecific_data_t *gData = (threadSpecific_data_t *)pthread_getspecific(threadSpecificKey); PTHREAD_TRACE_NP(Qp0zUprintf("foo(), threadSpecific data=%d %d\n", gData->threadSpecific1, gData->threadSpecific2);, PTHREAD_TRACE_INFO_NP); bar(); PTHREAD_TRACE_NP(Qp0zUprintf("foo(): This is an error tracepoint\n");, PTHREAD_TRACE_ERROR_NP); } void bar() { threadSpecific_data_t *gData = (threadSpecific_data_t *)pthread_getspecific(threadSpecificKey); PTHREAD_TRACE_NP(Qp0zUprintf("bar(), threadSpecific data=%d %d\n", gData->threadSpecific1, gData->threadSpecific2);, PTHREAD_TRACE_INFO_NP); PTHREAD_TRACE_NP(Qp0zUprintf("bar(): This is an error tracepoint\n"); Qp0zDumpStack("This thread's stack at time of error in bar()");, PTHREAD_TRACE_ERROR_NP); return; } void dataDestructor(void *data) { PTHREAD_TRACE_NP(Qp0zUprintf("dataDestructor: Free data\n");, PTHREAD_TRACE_INFO_NP); pthread_setspecific(threadSpecificKey, NULL); free(data); /* If doing verbose tracing we'll even write a message to the job log */ PTHREAD_TRACE_NP(Qp0zLprintf("Free'd the thread specific data\n");, PTHREAD_TRACE_VERBOSE_NP); } /* Call this testcase with an optional parameter 'PTHREAD_TRACING' */ /* If the PTHREAD_TRACING parameter is specified, then the */
/* Pthread tracing environment variable will be set, and the */ /* pthread tracing will be re initialized from its previous value. */ /* NOTE: We set the trace level to informational, tracepoints cut */ /* using PTHREAD_TRACE_NP at a VERBOSE level will NOT show up*/ int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; int i; threadSpecific_data_t *gData; char buffer[50]; PTHREAD_TRACE_NP(Qp0zUprintf("Enter Testcase - %s\n", argv[0]);, PTHREAD_TRACE_INFO_NP); if (argc == 2 && !strcmp("PTHREAD_TRACING", argv[1])) { /* Turn on internal pthread function tracing support */ /* Or, use ADDENVVAR, CHGENVVAR CL commands to set this envvar*/ sprintf(buffer, "QIBM_PTHREAD_TRACE_LEVEL=%d", PTHREAD_TRACE_INFO_NP); putenv(buffer); /* Refresh the Pthreads internal tracing with the environment */ /* variables value. */ pthread_trace_init_np(); } else { /* Trace only our application, not the Pthread code */ Qp0wTraceLevel = PTHREAD_TRACE_INFO_NP; } rc = pthread_key_create(&threadSpecificKey, dataDestructor); checkResults("pthread_key_create()\n", rc); for (i=0; i <NUMTHREADS; ++i) { PTHREAD_TRACE_NP(Qp0zUprintf("Create/start a thread\n");, PTHREAD_TRACE_INFO_NP); /* Create per-thread threadSpecific data and pass it to the thread */ gData = (threadSpecific_data_t *)malloc(sizeof (threadSpecific_data_t)); gData->threadSpecific1 = i; gData->threadSpecific2 = (i+1)*2; rc = pthread_create( &thread[i], NULL, theThread, gData); checkResults("pthread_create()\n", rc); PTHREAD_TRACE_NP(Qp0zUprintf("Wait for the thread to complete, " "and release their resources\n");, PTHREAD_TRACE_INFO_NP); rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); } pthread_key_delete(threadSpecificKey); PTHREAD_TRACE_NP(Qp0zUprintf("Main completed\n");, PTHREAD_TRACE_INFO_NP); return 0; } Output Use CL command DMPUSRTRC to output the following tracing information that the example creates. The DMPUSRTRC CL command causes the following information to be put into file QTEMP/QAP0ZDMP or to standard output depending on the options used for the CL command. Note the following:
q
The trace records are indented and labeled based on thread id plus a microsecond timestamp at the time the
tracepoint was cut. In the following trace record, the value 0000000D indicates the thread ID of the thread that created the tracepoint. The value 133520 indicates that the tracepoint occurred 133520 microseconds after the last timestamp indicator. 0000000D:133520 Create/start a thread
q
You can use the Pthread library tracepoints to debug incorrect calls to the Pthreads library from your application. The following trace output occurs when the optional parameter 'PTHREAD_TRACING' is NOT specified when calling this program. Since 'PTHREAD_TRACING' is not specified, the application directly sets the Qp0wTraceLevel external variable, causing only application level tracing to occur, and skiping any Pthreads library tracing.
User Trace Dump for job 096932/KULACK/PTHREADT. Size: 300K, Wrapped 0 times. --- 11/06/1998 11:06:57 --0000000D:133520 Create/start a thread 0000000D:293104 Wait for the thread to complete, and release their resources 0000000E:294072 Thread Entered 0000000E:294272 DB51A4C80A:001CD0 L:0008 Global Data 0000000E:294416 DB51A4C80A:001CD0 00000000 00000002 *................* 0000000E:294496 foo(), threadSpecific data=0 2 0000000E:294568 bar(), threadSpecific data=0 2 0000000E:294624 bar(): This is an error tracepoint 0000000E:294680 Stack Dump For Current Thread 0000000E:294736 Stack: This thread's stack at time of error in bar() 0000000E:333872 Stack: Library / Program Module Stmt Procedure 0000000E:367488 Stack: QSYS / QLESPI QLECRTTH 774 : LE_Create_Thread2__FP12crtth_parm_t 0000000E:371704 Stack: QSYS / QP0WPTHR QP0WPTHR 1008 : pthread_create_part2 0000000E:371872 Stack: KULACK / PTHREADT PTHREADT 19 : theThread__FPv 0000000E:371944 Stack: KULACK / PTHREADT PTHREADT 29 : foo__Fv 0000000E:372016 Stack: KULACK / PTHREADT PTHREADT 46 : bar__Fv 0000000E:372104 Stack: QSYS / QP0ZCPA QP0ZUDBG 87 : Qp0zDumpStack 0000000E:379248 Stack: QSYS / QP0ZSCPA QP0ZSCPA 276 : Qp0zSUDumpStack 0000000E:379400 Stack: QSYS / QP0ZSCPA QP0ZSCPA 287 : Qp0zSUDumpTargetStack 0000000E:379440 Stack: Completed 0000000E:379560 foo(): This is an error tracepoint 0000000E:379656 dataDestructor: Free data 0000000D:413816 Create/start a thread 0000000D:414408 Wait for the thread to complete, and release their resources 0000000F:415672 Thread Entered 0000000F:415872 DB51A4C80A:001CD0 L:0008 Global Data 0000000F:416024 DB51A4C80A:001CD0 00000001 00000004 *................* 0000000F:416104 foo(), threadSpecific data=1 4 0000000F:416176 bar(), threadSpecific data=1 4 0000000F:416232 bar(): This is an error tracepoint 0000000F:416288 Stack Dump For Current Thread
This thread's stack at time of error in Stmt 774 1008 19 29 46 87 276 287 : : : : : : : :
0000000F:416552 Stack: Library / Program Module Procedure 0000000F:416696 Stack: QSYS / QLESPI QLECRTTH LE_Create_Thread2__FP12crtth_parm_t 0000000F:416784 Stack: QSYS / QP0WPTHR QP0WPTHR pthread_create_part2 0000000F:416872 Stack: KULACK / PTHREADT PTHREADT theThread__FPv 0000000F:416952 Stack: KULACK / PTHREADT PTHREADT foo__Fv 0000000F:531432 Stack: KULACK / PTHREADT PTHREADT bar__Fv 0000000F:531544 Stack: QSYS / QP0ZCPA QP0ZUDBG Qp0zDumpStack 0000000F:531632 Stack: QSYS / QP0ZSCPA QP0ZSCPA Qp0zSUDumpStack 0000000F:531704 Stack: QSYS / QP0ZSCPA QP0ZSCPA Qp0zSUDumpTargetStack 0000000F:531744 Stack: Completed 0000000F:531856 foo(): This is an error tracepoint 0000000F:531952 dataDestructor: Free data 0000000D:532528 Main completed
Parameters
None.
Return Value
0 sched_yield() was successful. value sched_yield() was not successful. value is set to indicate the error condition.
Error Conditions
The sched_yield() API does not currently return an error.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_getschedparam()--Get Thread Scheduling Parameters
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <errno.h> #include "check.h" #define #define pthread_mutex_t int LOOPCONSTANT THREADS 1000 3
void *threadfunc(void *parm) { int loop = 0; int localProcessingCompleted = 0; int numberOfLocalProcessingBursts = 0; int processingCompletedThisBurst = 0; int rc; printf("Entered secondary thread\n"); for (loop=0; loop<LOOPCONSTANT; ++loop) { rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); /* Perform some not so important processing */ i++, j++, k++, l++; rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc); /* This work is not too important. Also, we just released a lock and would like to ensure that other threads get a chance in a more co-operative manner. This is an admittedly contrived example with no real purpose for doing the sched_yield(). */ sched_yield(); } printf("Finished secondary thread\n"); return NULL; } int main(int argc, char **argv) { pthread_t threadid[THREADS]; int rc=0; int loop=0; printf("Enter Testcase - %s\n", argv[0]); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); printf("Creating %d threads\n", THREADS); for (loop=0; loop<THREADS; ++loop) { rc = pthread_create(&threadid[loop], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } sleep(1); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc); printf("Wait for results\n"); for (loop=0; loop<THREADS; ++loop) { rc = pthread_join(threadid[loop], NULL); checkResults("pthread_join()\n", rc); } pthread_mutex_destroy(&mutex); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPSCHY0 Creating 3 threads Entered secondary thread Entered secondary thread Entered secondary thread Wait for results Finished secondary thread Finished secondary thread Finished secondary thread Main completed
pthread_getspecific()--Get Thread Local Storage Value by Key pthread_key_create()--Create Thread Local Storage Key pthread_key_delete()--Delete Thread Local Storage Key pthread_setspecific()--Set Thread Local Storage by Key
Parameters
key (Input) The thread local storage key returned from pthread_key_create()
Return Value
value pthread_getspecific() was successful. value is set to indicate the current thread specific data pointer stored at the key location. NULL pthread_getspecific() returned the null thread specific data value stored at the key location or the key was out of range.
Error Conditions
None.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_key_create()--Create Thread Local Storage Key pthread_key_delete()--Delete Thread Local Storage Key pthread_setspecific()--Set Thread Local Storage by Key
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h"
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_34.htm (1 of 3) [2/9/2001 1:59:15 PM]
#define pthread_key_t
NUMTHREADS tlsKey = 0;
void globalDestructor(void *value) { printf("In the globalDestructor\n"); free(value); pthread_setspecific(tlsKey, NULL); } void showGlobal(void) { void pthread_id_np_t
*global; tid;
global = pthread_getspecific(tlsKey); pthread_getunique_np((pthread_t *)global, &tid); printf("showGlobal: global data stored for thread 0x%.8x%.8x\n", tid); } void *threadfunc(void *parm) { int rc; int *myThreadDataStructure; pthread_t me = pthread_self(); printf("Inside secondary thread\n"); myThreadDataStructure = malloc(sizeof(pthread_t) + sizeof(int) * 10); memcpy(myThreadDataStructure, &me, sizeof(pthread_t)); pthread_setspecific(tlsKey, myThreadDataStructure); showGlobal(); pthread_exit(NULL); } int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; int i=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread local storage key\n"); rc = pthread_key_create(&tlsKey, globalDestructor); checkResults("pthread_key_create()\n", rc); /* The key can now be used from all threads */ printf("Create %d threads using joinable attributes\n", NUMTHREADS); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&thread[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } printf("Join to threads\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_join(thread[i], NULL);
checkResults("pthread_join()\n", rc); } printf("Delete a thread local storage key\n"); rc = pthread_key_delete(tlsKey); checkResults("pthread_key_delete()\n", rc); /* The key and any remaining values are now gone. */ printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPGETS0 Create a thread local storage key Create 3 threads using joinable attributes Join to threads Inside secondary thread showGlobal: global data stored for thread 0x000000000000000b In the globalDestructor Inside secondary thread showGlobal: global data stored for thread 0x000000000000000d In the globalDestructor Inside secondary thread showGlobal: global data stored for thread 0x000000000000000c In the globalDestructor Delete a thread local storage key Main completed
Parameters
key (Output) The address of the variable to contain the thread local storage key destructor (Input) The address of the function to act as a destructor for this thread local storage key
Return Value
0 pthread_key_create() was successful. value pthread_key_create() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_key_create() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EAGAIN]
The system did not have enough resources, or the maximum of PTHREAD_KEYS_MAX would have been exceeded. [ENOMEM] Not enough memory to create the key.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_getspecific()--Get Thread Local Storage Value by Key pthread_key_delete()--Delete Thread Local Storage Key pthread_setspecific()--Set Thread Local Storage by Key
Example
#define _MULTI_THREADED #include <pthread.h> #include <sched.h> #include <stdio.h> #include "check.h" pthread_key_t tlsKey = 0;
void globalDestructor(void *value) { printf("In the data destructor\n"); free(value); pthread_setspecific(tlsKey, NULL); } int main(int argc, char **argv) { int rc=0; int i=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread local storage key\n"); rc = pthread_key_create(&tlsKey, globalDestructor); checkResults("pthread_key_create()\n", rc); /* The key can now be used from all threads */ printf("printf("printf("printf("The key can now be used from all threads\n"); in the process to storage thread local\n"); (but global to all functions in that thread)\n"); storage\n");
printf("Delete a thread local storage key\n"); rc = pthread_key_delete(tlsKey); checkResults("pthread_key_delete()\n", rc); /* The key and any remaining values are now gone. */ printf("Main completed\n"); return 0; }
Output:
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_35.htm (2 of 3) [2/9/2001 1:59:15 PM]
Enter Testcase - QP0WTEST/TPKEYC0 Create a thread local storage key - The key can now be used from all threads - in the process to storage thread local - (but global to all functions in that thread) - storage Delete a thread local storage key Main completed
Parameters
key (Input) The thread local storage key returned from pthread_key_create()
Return Value
0 pthread_key_delete() was successful. value pthread_key_delete() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_key_delete() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. A destructor function is not called as a result of the application calling pthread_key_delete(). [EINVAL] The value specified for the argument is not correct. [ENOENT] An entry for the key is not currently allocated.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_getspecific()--Get Thread Local Storage Value by Key pthread_key_create()--Create Thread Local Storage Key pthread_setspecific()--Set Thread Local Storage by Key
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_key_t tlsKey = 0;
void globalDestructor(void *value) { printf("In global data destructor\n"); free(value); pthread_setspecific(tlsKey, NULL); } int main(int argc, char **argv) { int rc=0; int i=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread local storage key\n"); rc = pthread_key_create(&tlsKey, globalDestructor); checkResults("pthread_key_create()\n", rc); /* The key can now be used from all threads */ printf("Delete a thread local storage key\n"); rc = pthread_key_delete(tlsKey); checkResults("pthread_key_delete()\n", rc); printf("- The key should not be used from any thread\n"); printf("- after destruction.\n"); /* The key and any remaining values are now gone. */ printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPKEYD0 Create a thread local storage key Delete a thread local storage key - The key should not be used from any thread - after destruction. Main completed
Parameters
key (Input) The thread local storage key returned from pthread_key_create(). value (Input) The pointer to store at the key location for the calling thread.
Return Value
0 pthread_setspecific() was successful. value pthread_setspecific() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_setspecific() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the key is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_getspecific()--Get Thread Local Storage Value by Key pthread_key_create()--Create Thread Local Storage Key pthread_key_delete()--Delete Thread Local Storage Key
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" #define pthread_key_t NUMTHREADS tlsKey = 0; 3
void globalDestructor(void *value) { printf("In global destructor\n"); free(value); pthread_setspecific(tlsKey, NULL); } void showGlobal(void) { void pthread_id_np_t
*global; tid;
global = pthread_getspecific(tlsKey); pthread_getunique_np((pthread_t *)global, &tid); printf("showGlobal: global data stored for thread 0x%.8x %.8x\n", tid); } void *threadfunc(void *parm) { int rc; int *myThreadDataStructure; pthread_t me = pthread_self(); printf("Inside secondary thread\n"); myThreadDataStructure = malloc(sizeof(pthread_t) + sizeof(int) * 10); memcpy(myThreadDataStructure, &me, sizeof(pthread_t)); pthread_setspecific(tlsKey, myThreadDataStructure); showGlobal(); return NULL; } int main(int argc, char **argv) { pthread_t thread[NUMTHREADS]; int rc=0; int i=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create a thread local storage key\n"); rc = pthread_key_create(&tlsKey, globalDestructor); checkResults("pthread_key_create()\n", rc); /* The key can now be used from all threads */ printf("Create %d threads using joinable attributes\n", NUMTHREADS); for (i=0; i<NUMTHREADS; ++i) {
rc = pthread_create(&thread[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } printf("Join to threads\n"); for (i=0; i<NUMTHREADS; ++i) { rc = pthread_join(thread[i], NULL); checkResults("pthread_join()\n", rc); } printf("Delete a thread local storage key\n"); rc = pthread_key_delete(tlsKey); checkResults("pthread_key_delete()\n", rc); /* The key and any remaining values are now gone. */ printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPSETS0 Create a thread local storage key Create 3 threads using joinable attributes Join to threads Inside secondary thread showGlobal: global data stored for thread 0x00000000 0000011a In global destructor Inside secondary thread showGlobal: global data stored for thread 0x00000000 0000011b In global destructor Inside secondary thread showGlobal: global data stored for thread 0x00000000 0000011c In global destructor Delete a thread local storage key Main completed
For information about the examples included with the APIs, see the information on the API examples. The thread cancellation APIs are:
q q q q q q q q q
pthread_cancel()--Cancel Thread pthread_cleanup_peek_np()--Copy Cleanup Handler from Cancellation Cleanup Stack pthread_cleanup_pop()--Pop Cleanup Handler off of Cancellation Cleanup Stack pthread_cleanup_push()--Push Cleanup Handler onto Cancellation Cleanup Stack pthread_getcancelstate_np()--Get Cancel State pthread_setcancelstate()--Set Cancel State pthread_setcanceltype()--Set Cancel Type pthread_testcancel()--Create Cancellation Point pthread_test_exit_np()--Test Thread Exit Status
pthread_cancel()--Cancel Thread
pthread_cancel()--Cancel Thread
Syntax #include <pthread.h> int pthread_cancel(pthread_t thread); Threadsafe: Yes Signal Safe: No The pthread_cancel() function requests cancellation of the target thread. The target thread is canceled, based on its ability to be canceled. When cancelability is disabled, all cancels are held pending in the target thread until the thread changes the cancelability. When cancelability is deferred, all cancels are held pending in the target thread until the thread changes the cancelability, calls a function that is a cancellation point, or calls pthread_testcancel(), thus creating a cancellation point. When cancelability is asynchronous, all cancels are acted upon immediately, interrupting the thread with its processing. You should not use asynchronous thread cancellation via the PTHREAD_CANCEL_ASYNCHRONOUS option of pthread_setcanceltype() in your application. See the common user errors section of this document for more information. The following functions are cancellation points:
q q q q q q
After action is taken for the target thread to be canceled, the following events occur in that thread. 1. The thread invokes cancellation cleanup handlers with cancellation disabled until the last cancellation cleanup handler returns. The handlers are invoked in Last In, First Out (LIFO) order. 2. Data destructors are called for any thread-specific data entries that have a non NULL value for both the value and the destructor. 3. When the last cancellation cleanup handler returns, the thread is terminated and a status of PTHREAD_CANCELED is made available to any threads joining the target. 4. Any mutexes that are held by a thread that terminates, are abandoned and are no longer valid. Subsequent calls by other threads that attempt to acquire the abandoned mutex (pthread_mutex_lock() or pthread_mutex_trylock()) fail with an EOWNERTERM error. 5. Application visible process resources are not released. This includes but is not limited to mutexes, file descriptors, or any process level cleanup actions. A cancellation cleanup handler should not exit via longjmp() or siglongjmp(). In the OS/400 implementation of threads, the initial thread is special. Termination of the initial thread via pthread_exit(), pthread_cancel() or any other thread termination mechanism terminates the entire process.
Parameters
thread (Input) Pthread handle to the target thread
pthread_cancel()--Cancel Thread
Return Value
0 pthread_cancel() was successful. value pthread_cancel() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_cancel() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ESRCH] No thread could be found that matched the thread ID specified.
Related Information
q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cleanup_pop()--Pop Cleanup Handler off of Cancellation Cleanup Stack pthread_cleanup_push()--Push Cleanup Handler onto Cancellation Cleanup Stack pthread_exit()--Terminate Calling Thread pthread_setcancelstate()--Set Cancel State pthread_setcanceltype()--Set Cancel Type
Example
#include <pthread.h> #include <stdio.h> #include "check.h" void *threadfunc(void *parm) { printf("Entered secondary thread\n"); while (1) { printf("Secondary thread is looping\n"); pthread_testcancel(); sleep(1); } return NULL; } int main(int argc, char **argv) { pthread_t thread;
pthread_cancel()--Cancel Thread
int
rc=0;
printf("Entering testcase\n"); /* Create a thread using default attributes */ printf("Create thread using the NULL attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(2); printf("Cancel the thread\n"); rc = pthread_cancel(thread); checkResults("pthread_cancel()\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(3); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create thread using the NULL attributes Entered secondary thread Secondary thread is looping Secondary thread is looping Cancel the thread Main completed
Parameters
None.
Return Value
0 pthread_cleanup_peek_np() was successful. value pthread_cleanup_peek_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_cleanup_peek_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ENOENT] The cancellation cleanup stack is empty.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cleanup_pop()--Pop Cleanup Handler off of Cancellation Cleanup Stack pthread_cleanup_push()--Push Cleanup Handler onto Cancellation Cleanup Stack pthread_exit()--Terminate Calling Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void cleanupHandler1(void *arg) { printf("In Handler 1\n"); return; } void cleanupHandler2(void *arg) { printf("In Handler 2\n"); return; } void cleanupHandler3(void *arg) { printf("In Handler 3\n"); return; } int args[3] = {0,0,0}; int main(int argc, char **argv) { int rc=0; pthread_cleanup_entry_np_t entry; printf("Enter Testcase - %s\n", argv[0]); printf("Check for absence of cleanup handlers\n"); rc = pthread_cleanup_peek_np(&entry); if (rc != ENOENT) { printf("pthread_cleanup_peek_np(), expected ENOENT\n"); exit(1); } printf("Push some cancellation cleanup handlers\n"); pthread_cleanup_push(cleanupHandler1, &args[0]); pthread_cleanup_push(cleanupHandler2, &args[1]); printf("Check for cleanupHandler2\n"); rc = pthread_cleanup_peek_np(&entry); checkResults("pthread_cleanup_peek_np(2)\n", rc); if (entry.handler != cleanupHandler2 || entry.arg != &args[1]) { printf("Did not get expected handler(2) information!\n"); exit(1); } pthread_cleanup_push(cleanupHandler3, &args[2]); printf("Check for cleanupHandler3\n"); rc = pthread_cleanup_peek_np(&entry); checkResults("pthread_cleanup_peek_np(3)\n", rc); if (entry.handler != cleanupHandler3 || entry.arg != &args[2]) { printf("Did not get expected handler(3) information!\n"); exit(1); }
Output:
Enter Testcase - QP0WTEST/TPCLPP0 Check for absence of cleanup handlers Push some cancellation cleanup handlers Check for cleanupHandler2 Check for cleanupHandler3 Main completed
Parameters
execute (Input) Boolean value indicating whether the cancellation cleanup handler should be executed
Return Value
None.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread pthread_cleanup_push()--Push Cleanup Handler onto Cancellation Cleanup Stack pthread_exit()--Terminate Calling Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void cleanupHandler(void *arg) { printf("In the cleanup handler\n"); } void *threadfunc(void *parm) { printf("Entered secondary thread, you should see the cleanup handler\n"); pthread_cleanup_push(cleanupHandler, NULL); sleep(1); /* Simulate more code here */ pthread_cleanup_pop(1); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; printf("Enter Testcase - %s\n", argv[0]); /* Create a thread using default attributes */ printf("Create thread using the NULL attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(5); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPCLPO0 Create thread using the NULL attributes Entered secondary thread, you should see the cleanup handler In the cleanup handler Main completed
Parameters
routine (Input) The cancellation cleanup routine arg (Input) Argument that is passed to the start routine if it is invoked
Return Value
None.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread pthread_cleanup_pop()--Pop Cleanup Handler off of Cancellation Cleanup Stack pthread_exit()--Terminate Calling Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void cleanupHandler(void *arg) { printf("In the cleanup handler\n"); } void *threadfunc(void *parm) { printf("Entered secondary thread\n"); pthread_cleanup_push(cleanupHandler, NULL); while (1) { pthread_testcancel(); sleep(1); } pthread_cleanup_pop(0); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; printf("Enter Testcase - %s\n", argv[0]); /* Create a thread using default attributes */ printf("Create thread using the NULL attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(2); printf("Cancel the thread\n"); rc = pthread_cancel(thread); checkResults("pthread_cancel()\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(3); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPCLPU0 Create thread using the NULL attributes Entered secondary thread Cancel the thread In the cleanup handler Main completed
Parameters
cancelstate (Output) Address of the variable to receive the cancel state.
Return Value
0 pthread_getcancelstate_np() was successful. value pthread_getcancelstate_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_getcancelstate_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread
pthread_exit()--Terminate Calling Thread pthread_setcancelstate()--Set Cancel State pthread_setcanceltype()--Set Cancel Type pthread_testcancel()--Create Cancellation Point
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <except.h> #include <setjmp.h> #include "check.h" void int showCancelState(void); threadStatus=42;
void showCancelState(void) { int state, rc; rc = pthread_getcancelstate_np(&state); checkResults("pthread_getcancelstate_np()\n", rc); printf("current cancel state is %d\n", state); } void cleanupHandler2(void *p) { printf("In cancellation cleanup handler\n"); showCancelState(); return; } void *threadfunc(void *parm) { int rc, old; printf("Inside secondary thread\n"); showCancelState(); pthread_cleanup_push(cleanupHandler2, NULL); threadStatus = 0; printf("Calling pthread_exit() will allow cancellation " "cleanup handlers to run\n"); pthread_exit(__VOID(threadStatus)); pthread_cleanup_pop(0); return __VOID(-1); } int main(int argc, char **argv) { pthread_t thread; int rc=0; char c; void *status; printf("Enter Testcase - %s\n", argv[0]);
printf("Create thread that will demonstrate pthread_getcancelstate_np()\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(thread, &status); checkResults("pthread_join()\n", rc); if (__INT(status) != threadStatus) { printf("Got an unexpected return status from the thread!\n"); exit(1); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPGETCANS0 Create thread that will demonstrate pthread_getcancelstate_np() Inside secondary thread current cancel state is 0 Calling pthread_exit() will allow cancellation cleanup handlers to run In cancellation cleanup handler current cancel state is 1 Main completed
Parameters
state (Input) New cancel state (one of PTHREAD_CANCEL_ENABLE or PTHREAD_CANCEL_DISABLE) oldstate (Output) Address of variable to contain old cancel state. (NULL is allowed)
Return Value
0 pthread_setcancelstate() was successful. value pthread_setcancelstate() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_setcancelstate() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread pthread_exit()--Terminate Calling Thread pthread_setcanceltype()--Set Cancel Type pthread_testcancel()--Create Cancellation Point
Example
#include #include #include #include <pthread.h> <stdio.h> <unistd.h> "check.h"
void *threadfunc(void *parm) { int i = 0; printf("Entered secondary thread\n"); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); while (1) { printf("Secondary thread is looping\n"); pthread_testcancel(); sleep(1); if (++i == 5) { /* Since default cancel type is deferred, changing the state */ /* will allow the next cancellation point to cancel the thread */ printf("Cancel state set to ENABLE\n"); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); } } /* infinite */ return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; printf("Entering testcase\n"); /* Create a thread using default attributes */ printf("Create thread using the NULL attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(3); printf("Cancel the thread\n"); rc = pthread_cancel(thread); checkResults("pthread_cancel()\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(3); printf("Main completed\n"); return 0;
Output:
Entering testcase Create thread using the NULL attributes Entered secondary thread Secondary thread is looping Secondary thread is looping Secondary thread is looping Cancel the thread Secondary thread is looping Secondary thread is looping Cancel state set to ENABLE Main completed
The default cancelability state is deferred. When cancelability is disabled, all cancels are held pending in the target thread until the thread changes the cancelability. When cancelability is deferred, all cancels are held pending in the target thread until the thread changes the cancelability, calls a function which is a cancellation point or calls pthread_testcancel(), thus creating a cancellation point. When cancelability is asynchronous, all cancels are acted upon immediately, interrupting the thread with its processing. It is recommended that your application not use asynchronous thread cancellation via the PTHREAD_CANCEL_ASYNCHRONOUS option of pthread_setcanceltype(). See the common user errors section of this document for more information.
Parameters
type (Input) New cancel type (one of PTHREAD_CANCEL_DEFERRED or PTHREAD_CANCEL_ASYNCHRONOUS) oldtype (Output) Address of variable to contain old cancel type. (NULL is allowed)
Return Value
0 pthread_setcanceltype() was successful. value pthread_setcanceltype() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_setcanceltype() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread pthread_exit()--Terminate Calling Thread pthread_setcancelstate()--Set Cancel State pthread_testcancel()--Create Cancellation Point
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void cleanupHandler(void *parm) { int rc; printf("Inside cleanup handler, unlock mutex\n"); rc = pthread_mutex_unlock((pthread_mutex_t *)parm); checkResults("pthread_mutex_unlock\n", rc); } void *threadfunc(void *parm) { int rc; int oldtype; printf("Entered secondary thread, lock mutex\n"); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); pthread_cleanup_push(cleanupHandler, &mutex); /* We must assume there is a good reason for async. cancellability */ /* and also, we must assume that if we get interrupted, it is */ /* appropriate to unlock the mutex. More than likely it is not */ /* because we will have left some data structures in a strange state */ /* if we are async. interrupted while holding the mutex */ rc = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); checkResults("pthread_setcanceltype()\n", rc); printf("Secondary thread is now looping\n"); while (1) { sleep(1); } printf("Unexpectedly got out of loop!\n"); pthread_cleanup_pop(0); return NULL;
} int main(int argc, char **argv) { pthread_t thread; int rc=0; void *status; printf("Enter Testcase - %s\n", argv[0]); /* Create a thread using default attributes */ printf("Create thread using the NULL attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); /* sleep() is not a very robust way to wait for the thread */ sleep(1); printf("Cancel the thread\n"); rc = pthread_cancel(thread); checkResults("pthread_cancel()\n", rc); rc = pthread_join(thread, &status); if (status != PTHREAD_CANCELED) { printf("Unexpected thread status\n"); exit(1); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPSETCANT0 Create thread using the NULL attributes Entered secondary thread, lock mutex Secondary thread is now looping Cancel the thread Inside cleanup handler, unlock mutex Main completed
Parameters
None.
Return Value
None.
Error Conditions
None.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread pthread_setcancelstate()--Set Cancel State pthread_setcanceltype()--Set Cancel Type
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void cleanupHandler(void *parm) { printf("Inside cancellation cleanup handler\n");
} void *threadfunc(void *parm) { unsigned int i=0; int rc=0, oldState=0; printf("Entered secondary thread\n"); pthread_cleanup_push(cleanupHandler, NULL); rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); checkResults("pthread_setcancelstate()\n", rc); /* Allow cancel to be pending on this thread */ sleep(2); while (1) { printf("Secondary thread is now looping\n"); ++i; sleep(1); /* pthread_testcancel() has no effect until cancelability is enabled.*/ /* At that time, a call to pthread_testcancel() should result in the */ /* pending cancel being acted upon */ pthread_testcancel(); if (i == 5) { printf("Cancel state set to ENABLE\n"); rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&oldState); checkResults("pthread_setcancelstate(2)\n", rc); /* Now, cancellation points will allow pending cancels to get through to this thread */ } } /* infinite */ pthread_cleanup_pop(0); return NULL; } int main(int argc, char **argv) { pthread_t thread; int rc=0; void *status=NULL; printf("Enter Testcase - %s\n", argv[0]); /* Create a thread using default attributes */ printf("Create thread using the NULL attributes\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); sleep(1); printf("Cancel the thread\n"); rc = pthread_cancel(thread); checkResults("pthread_cancel()\n", rc); rc = pthread_join(thread, &status); if (status != PTHREAD_CANCELED) { printf("Thread returned unexpected result!\n"); exit(1); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPTESTC0 Create thread using the NULL attributes Entered secondary thread Cancel the thread Secondary thread is now looping Secondary thread is now looping Secondary thread is now looping Secondary thread is now looping Secondary thread is now looping Cancel state set to ENABLE Secondary thread is now looping Inside cancellation cleanup handler Main completed
Parameters
status Pointer to the parameter to receive the exit status if PTHREAD_STATUS_EXIT_NP is returned
Return Value
PTHREAD_STATUS_ACTIVE_NP The thread is currently not exiting. PTHREAD_STATUS_EXIT_NP The thread is currently exiting. value pthread_test_exit_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_test_exit_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The values specified for the argument are not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" int int int checkStatusFailed1=0; missedHandler1=1; thread1Status=42;
void cleanupHandler1(void *arg) { int rc; void *status; printf("Thread 1 - cleanup handler\n"); missedHandler1=0; rc = pthread_test_exit_np(&status); if (rc != PTHREAD_STATUS_EXIT_NP) { printf("Thread 1 - returned %d instead " "of PTHREAD_STATUS_EXIT_NP\n", rc); checkStatusFailed1 = 1; return; } if (__INT(status) != thread1Status) { printf("Thread 1 - status = %d\n" "Thread 1 - expected %d\n", __INT(status), thread1Status); checkStatusFailed1=1; } printf("Thread 1 - correctly got PTHREAD_STATUS_EXIT_NP " "and thread exit status of %d\n", thread1Status); } void *thread1func(void *parm) { printf("Thread 1 - Entered\n"); pthread_cleanup_push(cleanupHandler1, NULL); pthread_exit(__VOID(thread1Status)); pthread_cleanup_pop(0); return __VOID(0); } int main(int argc, char **argv) { pthread_t thread; int rc=0; void *status; printf("Enter Testcase - %s\n", argv[0]); rc = pthread_test_exit_np(&status); if (rc != PTHREAD_STATUS_ACTIVE_NP) { printf("We should always be in an ACTIVE status here! rc=%d\n", rc); exit(1); }
printf("Create the pthread_exit thread\n"); rc = pthread_create(&thread, NULL, thread1func, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(thread, &status); checkResults("pthread_join()\n", rc); if (__INT(status) != thread1Status) { printf("Wrong status from thread 1\n"); } if (checkStatusFailed1 || missedHandler1) { printf("The thread did not complete its test correctly! " " check=%d, missed=%d\n", checkStatusFailed1, missedHandler1); exit(1); } printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPTEXIT0 Create the pthread_exit thread Thread 1 - Entered Thread 1 - cleanup handler Thread 1 - correctly got PTHREAD_STATUS_EXIT_NP and thread exit status of 42 Main completed
type
PTHREAD_MUTEX_DEFAULT (PTHREAD_MUTEX_NORMAL)
For information about the examples included with the APIs, see the information on the API examples. To view the API list by description, see Mutex synchronization APIs. Mutex synchronization APIs by name
q q q q q q q q q q q q q q q q
pthread_mutexattr_destroy()--Destroy Mutex Attributes Object pthread_mutexattr_getkind_np()--Get Mutex Kind Attribute pthread_mutexattr_getname_np()--Get Name from Mutex Attributes Object pthread_mutexattr_getpshared()--Get Process Shared Attribute from Mutex Attributes Object pthread_mutexattr_gettype()--Get Mutex Type Attribute pthread_mutexattr_init()--Initialize Mutex Attributes Object pthread_mutexattr_setkind_np()--Get Mutex Kind Attribute pthread_mutexattr_setname_np()--Set Name in Mutex Attributes Object pthread_mutexattr_setpshared()--Set Process Shared Attribute in Mutex Attributes Object pthread_mutexattr_settype()--Set Mutex Type Attribute pthread_set_mutexattr_default_np()--Set Default Mutex Attributes Object Kind Attribute pthread_mutex_destroy()--Destroy Mutex pthread_mutex_init()--Initialize Mutex pthread_mutex_lock()--Lock Mutex pthread_mutex_timedlock_np()--Lock Mutex with Time-Out pthread_mutex_trylock()--Lock Mutex with No Wait
Parameters
attr (Input) Address of the mutex attributes object to be destroyed
Return Value
0 pthread_mutexattr_destroy() was successful. value pthread_mutexattr_destroy() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexattr_destroy() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_init()--Initialize Mutex Attributes Object pthread_mutex_init()--Initialize Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" pthread_mutex_t mutex;
int main(int argc, char **argv) { int rc=0; pthread_mutexattr_t mta; printf("Entering testcase\n"); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init\n", rc); printf("Create the mutex using a mutex attributes object\n"); rc = pthread_mutex_init(&mutex, &mta); checkResults("pthread_mutex_init(mta)\n", rc); printf("- At this point, the mutex with its default attributes\n"); printf("- Can be used from any threads that want to use it\n"); printf("Destroy mutex attribute\n"); rc = pthread_mutexattr_destroy(&mta); checkResults("pthread_mutexattr_destroy()\n", rc); printf("Destroy mutex\n"); rc = pthread_mutex_destroy(&mutex); checkResults("pthread_mutex_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create a default mutex attribute Create the mutex using a mutex attributes object - At this point, the mutex with its default attributes - Can be used from any threads that want to use it Destroy mutex attribute Destroy mutex Main completed
Parameters
attr (Input) Address of the mutex attributes object kind (Output) Address of the variable to receive the kind attribute
Return Value
0 pthread_mutexattr_getkind_np() was successful. value pthread_mutexattr_getkind_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexattr_getkind_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_init()--Initialize Mutex Attributes Object pthread_mutexattr_setkind_np()--Set Mutex Kind Attribute pthread_mutex_init()--Initialize Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" void showKind(pthread_mutexattr_t *mta) { int rc; int kind; printf("Check kind attribute\n"); rc = pthread_mutexattr_getkind_np(mta, &kind); checkResults("pthread_mutexattr_getpshared()\n", rc); printf("The pshared attributed is: "); switch (kind) { case PTHREAD_MUTEX_NONRECURSIVE_NP: printf("PTHREAD_MUTEX_NONRECURSIVE_NP\n"); break; case PTHREAD_MUTEX_RECURSIVE_NP: printf("PTHREAD_MUTEX_RECURSIVE_NP\n"); break; default : printf("! kind Error kind=%d !\n", kind); exit(1); } return; } int main(int argc, char { int pthread_mutexattr_t int **argv) rc=0; mta; pshared=0;
printf("Enter Testcase - %s\n", argv[0]); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init()\n", rc); showKind(&mta); printf("Change mutex kind attribute\n"); rc = pthread_mutexattr_setkind_np(&mta, PTHREAD_MUTEX_RECURSIVE_NP); checkResults("pthread_mutexattr_setkind()\n", rc); showKind(&mta); printf("Destroy mutex attribute\n"); rc = pthread_mutexattr_destroy(&mta); checkResults("pthread_mutexattr_destroy()\n", rc);
Output:
Enter Testcase - QP0WTEST/TPMTXAKN0 Create a default mutex attribute Check kind attribute The pshared attributed is: PTHREAD_MUTEX_NONRECURSIVE_NP Change mutex kind attribute Check kind attribute The pshared attributed is: PTHREAD_MUTEX_RECURSIVE_NP Destroy mutex attribute Main completed
Parameters
attr (Input) Address of the mutex attributes object name (Output) Address of a 16-byte character buffer to receive the name
Return Value
0 pthread_mutexattr_getname_np() was successful. value pthread_mutexattr_getname_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexattr_getname_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_init()--Initialize Mutex Attributes Object pthread_mutexattr_setname_np()--Set Name in Mutex Attributes Object pthread_mutex_init()--Initialize Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" int main(int argc, char { int pthread_mutexattr_t char **argv) rc=0; mta; mutexname[16];
printf("Entering testcase\n"); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init\n", rc); memset(mutexname, 0, sizeof(mutexname)); printf("Find out what the default name of the mutex is\n"); rc = pthread_mutexattr_getname_np(&mta, mutexname); checkResults("pthread_mutexattr_getname_np()\n", rc); printf("The default mutex name will be: %.15s\n", mutexname); printf("- At this point, mutexes created with this attribute\n"); printf("- will show up by name on many OS/400 debug and service screens\n"); printf("- The default attribute contains a special automatically\n"); printf("- incrementing name that changes for each mutex created in \n"); printf("- the process\n"); printf("Destroy mutex attribute\n"); rc = pthread_mutexattr_destroy(&mta); checkResults("pthread_mutexattr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create a default mutex attribute Find out what the default name of the mutex is The default mutex name is: QP0WMTX UNNAMED - At this point, mutexes created with this attribute - will show up by name on many OS/400 debug and service screens - The default attribute contains a special automatically - incrementing name that changes for each mutex created in - the process
Parameters
attr (Input) Address of the variable that contains the mutex attributes object pshared (Output) Address of the variable to contain the pshared attribute result
Return Value
0 pthread_mutexattr_getpshared() was successful. value pthread_mutexattr_getpshared() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexattr_getpshared() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_init()--Initialize Mutex Attributes Object
Example
#include <pthread.h> #include <stdio.h> #include "check.h" void showPshared(int pshared) { printf("The pshared attribute is: "); switch (pshared) { case PTHREAD_PROCESS_PRIVATE: printf("PTHREAD_PROCESS_PRIVATE\n"); break; case PTHREAD_PROCESS_SHARED: printf("PTHREAD_PROCESS_SHARED\n"); break; default : printf("! pshared Error !\n"); exit(1); } return; } int main(int argc, char { int pthread_mutexattr_t int **argv) rc=0; mta; pshared=0;
printf("Entering testcase\n"); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init()\n", rc); printf("Check pshared attribute\n"); rc = pthread_mutexattr_getpshared(&mta, &pshared); checkResults("pthread_mutexattr_getpshared()\n", rc); showPshared(pshared); printf("Destroy mutex attribute\n"); rc = pthread_mutexattr_destroy(&mta); checkResults("pthread_mutexattr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create a default mutex attribute Check pshared attribute The pshared attribute is: PTHREAD_PROCESS_PRIVATE Destroy mutex attribute Main completed
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_52.htm (2 of 2) [2/9/2001 2:01:56 PM]
Mutex Types
A normal mutex cannot be locked repeatedly by the owner. Attempts by a thread to relock an already held mutex, or to lock a mutex that was held by another thread when that thread terminated, cause a deadlock condition. A recursive mutex can be locked repeatedly by the owner. The mutex does not become unlocked until the owner has called pthread_mutex_unlock() for each successful lock request that it has outstanding on the mutex. An errorcheck mutex checks for deadlock conditions that occur when a thread relocks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex is an OS/400 extension to the errorcheck mutex type. An ownerterm mutex checks for deadlock conditions that occur when a thread relocks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex also checks for deadlock conditions that occur when a thread attempts to lock a mutex that was held by another thread when that thread terminated (an orphaned mutex). If a thread attempts to lock an orphaned mutex, the lock request fails with the EOWNERTERM error.
Parameters
attr (Input) Address of the mutex attributes object type (Output) Address of the variable to receive the type attribute
Return Value
0 pthread_mutexattr_gettype() was successful. value
pthread_mutexattr_gettype() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexatttr_gettype() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_init()--Initialize Mutex Attributes Object pthread_mutexattr_settype()--Set Mutex Type Attribute pthread_mutex_init()--Initialize Mutex
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" int showType(pthread_mutexattr_t *mta) { int rc; int type; printf("Check type attribute\n"); rc = pthread_mutexattr_gettype(mta, &type); checkResults("pthread_mutexattr_gettype()\n", rc); printf("The type attributed is: "); switch (type) { case PTHREAD_MUTEX_NORMAL: printf("PTHREAD_MUTEX_NORMAL (DEFAULT)\n"); break; case PTHREAD_MUTEX_RECURSIVE: printf("PTHREAD_MUTEX_RECURSIVE\n"); break; case PTHREAD_MUTEX_ERRORCHECK: printf("PTHREAD_MUTEX_ERRORCHECK\n"); break; case PTHREAD_MUTEX_OWNERTERM_NP: printf("PTHREAD_MUTEX_OWNERTERM_NP\n"); break; default : printf("! type Error type=%d !\n", type); exit(1); } return type; } int main(int argc, char **argv) { int rc=0; pthread_mutexattr_t mta;
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_53.htm (2 of 4) [2/9/2001 2:01:56 PM]
printf("Enter Testcase - %s\n", argv[0]); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init()\n", rc); printf("Change mutex type attribute to recursive\n"); rc = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); checkResults("pthread_mutexattr_settype()\n", rc); showType(&mta); rc = pthread_mutexattr_setname_np(&mta, "RECURSIVE ONE"); checkResults("pthread_mutexattr_setname_np()\n", rc); printf("Create the named, recursive mutex\n"); rc = pthread_mutex_init(&mutex, &mta); checkResults("pthread_mutex_init()\n", rc); printf("Lock the named, recursive mutex\n"); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock() 1\n", rc); printf("ReLock the named, recursive mutex\n"); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock() 2\n", rc); printf("Trylock the named, recursive mutex\n"); rc = pthread_mutex_trylock(&mutex); checkResults("pthread_mutex_trylock()\n", rc); printf("Timedlock the named, recursive mutex\n"); ts.tv_sec = 5; ts.tv_nsec = 0; rc = pthread_mutex_timedlock_np(&mutex, &ts); checkResults("pthread_mutex_timedlock_np()\n", rc); printf("Sleeping for a short time holding the recurive mutex\n"); printf("Use DSPJOB, option 19 to see the held mutex\n"); sleep(30); printf("Unlock the mutex 4 times\n"); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock() 1\n", rc); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock() 2\n", rc); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock() 3\n", rc); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock() 4\n", rc); printf("Cleanup\n"); rc = pthread_mutex_destroy(&mutex); checkResults("pthread_mutex_destroy()\n", rc);
Output
Enter Testcase - QP0WTEST/TPMTXTYP0 Create a default mutex attribute Change mutex type attribute to recursive Check type attribute The type attributed is: PTHREAD_MUTEX_RECURSIVE Create the named, recursive mutex Lock the named, recursive mutex ReLock the named, recursive mutex Trylock the named, recursive mutex Timedlock the named, recursive mutex Sleeping for a short time holding the recurive mutex Use DSPJOB, option 19 to see the held mutex Unlock the mutex 4 times Cleanup Main completed
Parameters
attr (Input/Output) Address of the variable to contain the mutex attributes object
Return Value
0 pthread_mutexattr_init() was successful. value pthread_mutexattr_init() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexattr_init() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_destroy()--Destroy Mutex Attributes Object pthread_mutex_destroy()--Destroy Mutex pthread_mutex_init()--Initialize Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" pthread_mutex_t mutex;
int main(int argc, char **argv) { int rc=0; pthread_mutexattr_t mta; printf("Entering testcase\n"); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init\n", rc); printf("Create the mutex using a mutex attributes object\n"); rc = pthread_mutex_init(&mutex, &mta); checkResults("pthread_mutex_init(mta)\n", rc); printf("- At this point, the mutex with its default attributes\n"); printf("- Can be used from any threads that want to use it\n"); printf("Destroy mutex attribute\n"); rc = pthread_mutexattr_destroy(&mta); checkResults("pthread_mutexattr_destroy()\n", rc); printf("Destroy mutex\n"); rc = pthread_mutex_destroy(&mutex); checkResults("pthread_mutex_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create a default mutex attribute Create the mutex using a mutex attributes object - At this point, the mutex with its default attributes - Can be used from any threads that want to use it Destroy mutex attribute Destroy mutex Main completed
Parameters
attr (Input) Address of the mutex attributes object kind (Input) Variable containing the kind attribute.
Return Value
0 pthread_mutexattr_setkind_np() was successful. value pthread_mutexattr_setkind_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexattr_setkind_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_getkind_np()--Get Mutex Kind Attribute pthread_mutex_init()--Initialize Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" void showKind(pthread_mutexattr_t *mta) { int rc; int kind; printf("Check kind attribute\n"); rc = pthread_mutexattr_getkind_np(mta, &kind); checkResults("pthread_mutexattr_getpshared()\n", rc); printf("The pshared attributed is: "); switch (kind) { case PTHREAD_MUTEX_NONRECURSIVE_NP: printf("PTHREAD_MUTEX_NONRECURSIVE_NP\n"); break; case PTHREAD_MUTEX_RECURSIVE_NP: printf("PTHREAD_MUTEX_RECURSIVE_NP\n"); break; default : printf("! kind Error kind=%d !\n", kind); exit(1); } return; } int main(int argc, char { int pthread_mutexattr_t int **argv) rc=0; mta; pshared=0;
printf("Enter Testcase - %s\n", argv[0]); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init()\n", rc); showKind(&mta); printf("Change mutex kind attribute\n"); rc = pthread_mutexattr_setkind_np(&mta, PTHREAD_MUTEX_RECURSIVE_NP); checkResults("pthread_mutexattr_setkind()\n", rc); showKind(&mta); printf("Destroy mutex attribute\n"); rc = pthread_mutexattr_destroy(&mta); checkResults("pthread_mutexattr_destroy()\n", rc); printf("Main completed\n");
return 0; }
Output:
Enter Testcase - QP0WTEST/TPMTXAKN0 Create a default mutex attribute Check kind attribute The pshared attributed is: PTHREAD_MUTEX_NONRECURSIVE_NP Change mutex kind attribute Check kind attribute The pshared attributed is: PTHREAD_MUTEX_RECURSIVE_NP Destroy mutex attribute Main completed
Parameters
attr (Input) Address of the mutex attributes object name (Input) Address of a null terminated character buffer containing the name
Return Value
0 pthread_mutexattr_setname_np() was successful. value pthread_mutexattr_setname_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexattr_setname_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_getname_np()--Get Name from Mutex Attributes Object pthread_mutex_init()--Initialize Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" int main(int argc, char { int pthread_mutexattr_t char **argv) rc=0; mta; mutexname[16];
printf("Entering testcase\n"); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init\n", rc); memset(mutexname, 0, sizeof(mutexname)); printf("Find out what the default name of the mutex is\n"); rc = pthread_mutexattr_getname_np(&mta, mutexname); checkResults("pthread_mutexattr_getname_np()\n", rc); printf("The default mutex name will be: %.15s\n", mutexname); printf("- At this point, mutexes created with this attribute\n"); printf("- will show up by name on many OS/400 debug and service screens\n"); printf("- The default attribute contains a special automatically\n"); printf("- incrementing name that changes for each mutex created in \n"); printf("- the process\n"); printf("Destroy mutex attribute\n"); rc = pthread_mutexattr_destroy(&mta); checkResults("pthread_mutexattr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create a default mutex attribute Find out what the default name of the mutex is The default mutex name will be: QP0WMTX UNNAMED The new mutex name will be: <My Mutex> Destroy mutex attribute Main completed
Parameters
attr (Input) Address of the variable containing the mutex attributes object pshared (Input) One of PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE
Return Value
0 pthread_mutexattr_setpshared() was successful. value pthread_mutexattr_setpshared() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexattr_setpshared() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_getpshared()--Get Process Shared Attribute from Mutex Attributes Object
pthread_mutex_init()--Initialize Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" void showPshared(pthread_mutexattr_t *mta) { int rc; int pshared; printf("Check pshared attribute\n"); rc = pthread_mutexattr_getpshared(mta, &pshared); checkResults("pthread_mutexattr_getpshared()\n", rc); printf("The pshared attributed is: "); switch (pshared) { case PTHREAD_PROCESS_PRIVATE: printf("PTHREAD_PROCESS_PRIVATE\n"); break; case PTHREAD_PROCESS_SHARED: printf("PTHREAD_PROCESS_SHARED\n"); break; default : printf("! pshared Error !\n"); exit(1); } return; } int main(int argc, char { int pthread_mutexattr_t int **argv) rc=0; mta; pshared=0;
printf("Entering testcase\n"); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init()\n", rc); showPshared(&mta); printf("Change pshared attribute\n"); rc = pthread_mutexattr_setpshared(&mta, PTHREAD_PROCESS_SHARED); checkResults("pthread_mutexattr_setpshared()\n", rc); showPshared(&mta); printf("Destroy mutex attribute\n"); rc = pthread_mutexattr_destroy(&mta); checkResults("pthread_mutexattr_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create a default mutex attribute Check pshared attribute The pshared attribute is: PTHREAD_PROCESS_PRIVATE Change pshared attribute The pshared attribute is: PTHREAD_PROCESS_SHARED Destroy mutex attribute Main completed
Mutex Types
A normal mutex cannot be locked repeatedly by the owner. Attempts by a thread to relock an already held mutex, or to lock a mutex that was held by another thread when that thread terminated result in a deadlock condition. A recursive mutex can be locked repeatedly by the owner. The mutex does not become unlocked until the owner has called pthread_mutex_unlock() for each successful lock request that it has outstanding on the mutex. An errorcheck mutex checks for deadlock conditions that occur when a thread re-locks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error An ownerterm mutex is an OS/400 extension to the errorcheck mutex type. An ownerterm mutex checks for deadlock conditions that occur when a thread re-locks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex also checks for deadlock conditions that occur when a thread attempts to lock a mutex that was held by another thread when that thread terminated (an orphaned mutex). If a thread attempts to lock an orphaned mutex, the lock request fails with the EOWNERTERM error.
Parameters
attr (Input) Address of the mutex attributes object type (Input) Address of the type attribute to be set.
Return Value
0 pthread_mutexattr_settype() was successful. value
pthread_mutexattr_settype() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutexatttr_settype() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_gettype()--Get Mutex Type Attribute pthread_mutex_init()--Initialize Mutex
Example
See pthread_mutexattr_gettype() for an example.
Parameters
kind (Input) Variable containing the kind attribute
Return Value
0 pthread_set_mutexattr_default() was successful. value pthread_set_mutexattr_default() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_set_mutexattr_default() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutexattr_setkind_np()--Set Mutex Kind Attribute pthread_mutex_init()--Initialize Mutex
pthread_mutex_destroy()--Destroy Mutex
pthread_mutex_destroy()--Destroy Mutex
Syntax #include <pthread.h> int pthread_mutex_destroy(pthread_mutex_t *mutex); Threadsafe: Yes Signal Safe: Yes The pthread_mutex_destroy() function destroys the named mutex. The destroyed mutex can no longer be used. If pthread_mutex_destroy() is called on a mutex that is locked by another thread, the request fails with an EBUSY error. If the calling thread has the mutex locked, any other threads waiting for the mutex via a call to pthread_mutex_lock() at the time of the call to pthread_mutex_destroy() fails with the EDESTROYED error. Mutex initialization using the PTHREAD_MUTEX_INITIALIZER does not immediately initialize the mutex. Instead, on first use, pthread_mutex_lock() or pthread_mutex_trylock() branches into a slow path and causes the initialization of the mutex. Because a mutex is not just a simple memory object and requires that some resources be allocated by the system, an attempt to call pthread_mutex_destroy() or pthread_mutex_unlock() on a mutex that has statically initialized using PTHREAD_MUTEX_INITIALER and was not yet locked causes an EINVAL error. Every mutex must eventually be destroyed with pthread_mutex_destroy(). The machine eventually detects the error if a mutex is not destroyed, but the storage is deallocated or corrupted. The machine then creates LIC log synchronization entries that indicate the failure to help debug the problem. Large numbers of these entries can affect system performance and hinder debug capabilities for other system problems. Always use pthread_mutex_destroy() before freeing mutex storage to prevent these debug LIC log entries. Once a mutex is created, it cannot be validly copied or moved to a new location.
Parameters
mutex (Input) Address of the mutex to be destroyed
Return Value
0 pthread_mutex_destroy() was successful. value pthread_mutex_destroy() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutex_destroy() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EBUSY] The mutex is currently owned by another thread. [EINVAL] The value specified for the argument is not correct.
pthread_mutex_destroy()--Destroy Mutex
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutex_init()--Initialize Mutex pthread_mutex_lock()--Lock Mutex pthread_mutex_trylock()--Lock Mutex with No Wait pthread_mutex_unlock()--Unlock Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" pthread_mutex_t mutex;
int main(int argc, char **argv) { int rc=0; pthread_mutexattr_t mta; printf("Entering testcase\n"); printf("Create the mutex using the NULL attributes (default)\n"); rc = pthread_mutex_init(&mutex, NULL); checkResults("pthread_mutex_init(NULL)\n", rc); printf("Destroy all mutexes\n"); pthread_mutex_destroy(&mutex); checkResults("pthread_mutex_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create the mutex using the NULL attributes (default) Destroy all mutexes Main completed
pthread_mutex_init()--Initialize Mutex
pthread_mutex_init()--Initialize Mutex
Syntax #include <pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; Threadsafe: Yes Signal Safe: Yes The pthread_mutex_init() function initializes a mutex with the specified attributes for use. The new mutex may be used immediately for serializing critical resources. If attr is specified as NULL, all attributes are set to the default mutex attributes for the newly created mutex. With these declarations and initialization: pthread_mutex_t mutex2; pthread_mutex_t mutex3; pthread_mutexattr_t mta; pthread_mutexattr_init(&mta); The following three mutex initialization mechanisms have equivalent function. pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_init(&mutex2, NULL); pthread_mutex_init(&mutex3, &mta); All three mutexes are created with the default mutex attributes. Every mutex must eventually be destroyed with pthread_mutex_destroy(). The machine eventually detects the error if a mutex is not destroyed. Large numbers of these entries can affect system performance. Always use pthread_mutex_destroy() before freeing or reusing mutex storage. Once a mutex is created, it cannot be validly copied or moved to a new location. If the mutex is copied or moved to a new location, the new object is not valid and cannot be used. Attempts to use the new object result in the EINVAL error. Mutex initialization using the PTHREAD_MUTEX_INITIALIZER does not immediately initialize the mutex. Instead, on first use, the pthread_mutex_lock() or pthread_mutex_trylock() functions branch into a slow path and cause the initialization of the mutex. Because a mutex is not just a simple memory object and requires that some resources be allocated by the system, an attempt to call pthread_mutex_destroy() or pthread_mutex_unlock() on a mutex that was statically initialized using PTHREAD_MUTEX_INITIALER and was not yet locked causes an EINVAL error.
Parameters
mutex (Input) The address of the variable to contain a mutex object. attr (Input) The address of the variable containing the mutex attributes object.
pthread_mutex_init()--Initialize Mutex
Return Value
0 pthread_mutex_init() was successful. value pthread_mutex_init() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutex_init() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ENOMEM] The system cannot allocate the resources required to create the mutex.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutex_destroy()--Destroy Mutex pthread_mutex_lock()--Lock Mutex pthread_mutex_trylock()--Lock Mutex with No Wait pthread_mutex_unlock()--Unlock Mutex
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_mutex_t pthread_mutex_t pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; mutex2; mutex3;
int main(int argc, char **argv) { int rc=0; pthread_mutexattr_t mta; printf("Enter Testcase - %s\n", argv[0]); printf("Create a default mutex attribute\n"); rc = pthread_mutexattr_init(&mta); checkResults("pthread_mutexattr_init\n", rc); printf("Create the mutexes using the default mutex attributes\n"); printf("First mutex created via static PTHREAD_MUTEX_INITIALIZER\n"); printf("Create the mutex using the NULL attributes (default)\n"); rc = pthread_mutex_init(&mutex3, NULL);
pthread_mutex_init()--Initialize Mutex
checkResults("pthread_mutex_init(NULL)\n", rc); printf("Create the mutex using a mutex attributes object\n"); rc = pthread_mutex_init(&mutex2, &mta); checkResults("pthread_mutex_init(mta)\n", rc); printf("- At this point, all mutexes can be used with their\n"); printf("- default attributes from any threads that want to\n"); printf("- use them\n"); printf("Destroy all mutexes\n"); pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex2); pthread_mutex_destroy(&mutex3); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPMTXINI0 Create a default mutex attribute Create the mutexes using the default mutex attributes First mutex created via static PTHREAD_MUTEX_INITIALIZER Create the mutex using the NULL attributes (default) Create the mutex using a mutex attributes object - At this point, all mutexes can be used with their - default attributes from any threads that want to - use them Destroy all mutexes Main completed
pthread_mutex_lock()--Lock Mutexe
pthread_mutex_lock()--Lock Mutex
Syntax #include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); Threadsafe: Yes Signal Safe: Yes The pthread_mutex_lock() function acquires ownership of the mutex specified. If the mutex is currently locked by another thread, the call to pthread_mutex_lock() blocks until that thread relinquishes ownership via a call to pthread_mutex_unlock(). If a signal is delivered to a thread while that thread is waiting for a mutex, when the signal handler returns, the wait resumes. pthread_mutex_lock() does not return EINTR like some other blocking function calls. Use the CL command WRKJOB, option 20, to help you debug mutex deadlocks. Destroying a held mutex is a common way to serialize destruction of objects that are protected by that mutex. This action is allowed. The call to pthread_mutex_lock() may fail with the EDESTROYED error if the mutex is destroyed by the thread that was currently holding it. Mutex initialization using the PTHREAD_MUTEX_INITIALIZER does not immediately initialize the mutex. Instead, on first use, pthread_mutex_timedlock_np() or pthread_mutex_lock() or pthread_mutex_trylock() branches into a slow path and causes the initialization of the mutex. Because a mutex is not just a simple memory object and requires that some resources be allocated by the system, an attempt to call pthread_mutex_destroy() or pthread_mutex_unlock() on a mutex that was statically initialized using PTHREAD_MUTEX_INITIALER and was not yet locked causes an EINVAL error. A pthread mutex is a structure of type pthread_mutex_t that implement a behavior based on the Pthread mutexes. An MI mutex is a structure built into the machine that implement a similar sort of serialization construct. The maximum number of recursive locks by the owning thread is 32,767. When this number is exceeded, attempts to lock the mutex return the ERECURSE error.
Mutex Types
A normal mutex cannot be locked repeatedly by the owner. Attempts by a thread to relock an already held mutex, or to lock a mutex that was held by another thread when that thread terminated, result in a deadlock condition. A recursive mutex can be locked repeatedly by the owner. The mutex does not become unlocked until the owner has called pthread_mutex_unlock() for each successful lock request that it has outstanding on the mutex. An errorcheck mutex checks for deadlock conditions that occur when a thread relocks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error An ownerterm mutex is an OS/400 extension to the errorcheck mutex type. An ownerterm mutex checks for deadlock conditions that occur when a thread relocks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex also checks for deadlock conditions that occur when a thread attempts to lock a mutex that was held by another thread when that thread terminated (an orphaned mutex). If a thread attempts to lock an orphaned mutex, the lock request fails with the EOWNERTERM error. When a thread terminates the holding of a mutex lock on a normal or errorcheck mutex, other threads that wait for that mutex will block forever. The pthreads run-time simulates the deadlock that has occurred in your application. When you are attempting to debug these deadlock scenarios, the CL command WRKJOB, option 20 shows the thread as in a condition wait. Displaying the call stack shows that the function deadlockedOnOrphanedMutex is in the call stack. When a thread attempts to acquire a normal mutex that it already holds, the thread will block forever. The pthreads
pthread_mutex_lock()--Lock Mutexe
run-time simulates the deadlock that has occurred in your application. When you are attempting to debug these deadlock scenarios, the CL command WRKJOB, option 20, shows the thread as in a condition wait. Displaying the call stack will show that the function deadlockedOnAlreadyLockedMutex is in the call stack. To change these behaviors, use an errorcheck or ownerterm mutex type.
Parameters
mutex (Input) The address of the mutex to lock
Return Value
0 pthread_mutex_lock() was successful. value pthread_mutex_lock() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutex_lock() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EDESTROYED] While waiting for the mutex lock to be satisfied, the mutex was destroyed. [EOWNERTERM] A thread terminated the holding of the mutex, and the mutex is an ownerterm mutex type. [EDEADLK] A thread attempted to relock an already held mutex, and the mutex is an errorcheck mutex type. [ERECURSE] The recursive mutex cannot be recursively locked again.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutex_destroy()--Destroy Mutex pthread_mutex_init()--Initialize Mutex pthread_mutex_trylock()--Lock Mutex with No Wait pthread_mutex_unlock()--Unlock Mutex
pthread_mutex_lock()--Lock Mutexe
Example
#include <pthread.h> #include <stdio.h> #include "check.h" /* This example shows the corruption that can result if no serialization is done and also shows the use of pthread_mutex_lock(). Call it with no parameters to use pthread_mutex_lock() to protect the critical section, or 1 or more parameters to show data corruption that occurs without locking. */ #define LOOPCONSTANT 100000 #define THREADS 10 pthread_mutex_t int int mutex = PTHREAD_MUTEX_INITIALIZER; i,j,k,l; uselock=1;
void *threadfunc(void *parm) { int loop = 0; int rc; for (loop=0; loop<LOOPCONSTANT; ++loop) { if (uselock) { rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); } ++i; ++j; ++k; ++l; if (uselock) { rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc); } } return NULL; } int main(int argc, char **argv) { pthread_t threadid[THREADS]; int rc=0; int pthread_attr_t loop=0; pta;
printf("Entering testcase\n"); printf("Give any number of parameters to show data corruption\n"); if (argc != 1) { printf("A parameter was specified, no serialization is being done!\n"); uselock = 0; } pthread_attr_init(&pta); pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE); printf("Creating %d threads\n", THREADS); for (loop=0; loop<THREADS; ++loop) { rc = pthread_create(&threadid[loop], &pta, threadfunc, NULL);
pthread_mutex_lock()--Lock Mutexe
checkResults("pthread_create()\n", rc); } printf("Wait for results\n"); for (loop=0; loop<THREADS; ++loop) { rc = pthread_join(threadid[loop], NULL); checkResults("pthread_join()\n", rc); } printf("Cleanup and show results\n"); pthread_attr_destroy(&pta); pthread_mutex_destroy(&mutex); printf("\nUsing %d threads and LOOPCONSTANT = %d\n", THREADS, LOOPCONSTANT); printf("Values are: (should be %d)\n", THREADS * LOOPCONSTANT); printf(" ==>%d, %d, %d, %d\n", i, j, k, l); printf("Main completed\n"); return 0; }
Output:
Entering testcase Give any number of parameters to show data corruption Creating 10 threads Wait for results Cleanup and show results Using 10 threads and LOOPCONSTANT = 100000 Values are: (should be 1000000) ==>1000000, 1000000, 1000000, 1000000 Main completed
Output:
Mutex Types
A normal mutex cannot be locked repeatedly by the owner. Attempts by a thread to relock an already held mutex, or to lock a mutex that was held by another thread when that thread terminated result in a deadlock condition. A recursive mutex can be locked repeatedly by the owner. The mutex does not become unlocked until the owner has called pthread_mutex_unlock() for each successful lock request that it has outstanding on the mutex. An errorcheck mutex checks for deadlock conditions that occur when a thread re-locks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error An ownerterm mutex is an OS/400 extension to the errorcheck mutex type. An ownerterm mutex checks for deadlock conditions that occur when a thread re-locks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex also checks for deadlock conditions that occur when a thread attempts to lock a mutex that was held by another thread when that thread terminated (an orphaned mutex). If a thread attempts to lock an orphaned mutex, the lock request fails with the EOWNERTERM error.
When a thread terminates holding a mutex lock on a normal or errorcheck mutex, other threads that wait for that mutex will block forever. The pthreads run-time simulates the deadlock that has occurred in your application. When attempting to debug these deadlock scenarios, the CL command WRKJOB, option 20 will show the thread as in a condition wait. Displaying the call stack will show that the function deadlockedOnOrphanedMutex is in the call stack. When a thread attempts to acquire a normal mutex that it already holds, the thread will block forever. The pthreads run-time simulates the deadlock that has occurred in your application. When attempting to debug these deadlock scenarios, the CL command WRKJOB, option 20 will show the thread as in a condition wait. Displaying the call stack will show that the function deadlockedOnAlreadyLockedMutex is in the call stack. In order to change these behaviors, use an errorcheck or ownerterm mutex type.
Parameters
mutex (Input) The address of the mutex to lock
Return Value
0 pthread_mutex_timedlock_np() was successful. value pthread_mutex_timedlock_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutex_timedlock_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EDESTROYED] While waiting for the mutex lock to be satisfied, the mutex was destroyed. [EBUSY] The attempt to lock the mutex timed out because the mutex was already locked. [EOWNERTERM] A thread terminated holding the mutex, and the mutex is an ownerterm mutex type. [EDEADLK] A thread attempted to relock an already held mutex, and the mutex is an errorcheck mutex type. [ERECURSE] The recursive mutex cannot be recursively locked again.
Related Information
q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutex_destroy()--Destroy Mutex pthread_mutex_init()--Initialize Mutex pthread_mutex_lock()--Lock Mutex pthread_mutex_trylock()--Lock Mutex with No Wait pthread_mutex_unlock()--Unlock Mutex
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *threadFunc(void *parm) { int rc; int i; struct timespec deltatime; deltatime.tv_sec = 5; deltatime.tv_nsec = 0; printf("Timed lock the mutex from a secondary thread\n"); rc = pthread_mutex_timedlock_np(&mutex, &deltatime); if (rc != EBUSY) { printf("Got an incorrect return code from pthread_mutex_timedlock_np\n"); } printf("Thread mutex timeout\n"); return 0; } int main(int argc, char **argv) { int rc=0; pthread_t thread; printf("Enter Testcase - %s\n", argv[0]); printf("Acquire the mutex in the initial thread\n"); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc), printf("Create a thread\n"); rc = pthread_create(&thread, NULL, threadFunc, NULL); checkResults("pthread_create()\n", rc); printf("Join to the thread\n"); rc = pthread_join(thread, NULL); checkResults("pthread_join()\n", rc);
Output:
Enter Testcase - QP0WTEST/TPMTXTIM0 Acquire the mutex in the initial thread Create a thread Join to the thread Timed lock the mutex from a secondary thread Thread mutex timeout Destroy mutex Main completed
Mutex Types
A normal mutex cannot be locked repeatedly by the owner. Attempts by a thread to relock an already held mutex, or to lock a mutex that was held by another thread when that thread terminated, cause a deadlock condition. A recursive mutex can be locked repeatedly by the owner. The mutex does not become unlocked until the owner has called pthread_mutex_unlock() for each successful lock request that it has outstanding on the mutex. An errorcheck mutex checks for deadlock conditions that occur when a thread relocks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex is an OS/400 extension to the errorcheck mutex type. An ownerterm mutex checks for deadlock conditions that occur when a thread relocks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex also checks for deadlock conditions that occur when a thread attempts to lock a mutex that was held by another thread when that thread terminated (an orphaned mutex). If a thread attempts to lock an orphaned mutex, the lock request fails with the EOWNERTERM error. When a thread terminates the holding of a mutex lock on a normal or errorcheck mutex, other threads that wait for that mutex will block forever. The pthreads run-time simulates the deadlock that has occurred in your application. When you are attempting to debug these deadlock scenarios, the CL command WRKJOB, option 20, shows the thread as in a condition wait. Displaying the call stack shows that the function deadlockedOnOrphanedMutex is in the call stack. When a thread attempts to acquire a normal mutex that it already holds, the thread will block forever. The pthreads run-time simulates the deadlock that has occurred in your application. When you are attempting to debug these deadlock scenarios, the CL command WRKJOB, option 20, shows the thread as in a condition wait. Displaying the call stack shows that the function deadlockedOnAlreadyLockedMutex is in the call stack. To change these behaviors, use an errorcheck or ownerterm mutex type.
Parameters
mutex (Input) Address of the mutex to lock
Return Value
0 pthread_mutex_trylock() was successful. value pthread_mutex_trylock() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutex_trylock() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EBUSY] The mutex is currently locked by another thread. A thread terminated the holding of the mutex, and the mutex is an ownerterm mutex type. A thread attempted to relock an already held mutex, and the mutex is an errorcheck mutex type. [ERECURSE] The recursive mutex cannot be recursively locked again.
Related Information
q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutex_destroy()--Destroy Mutex pthread_mutex_init()--Initialize Mutex pthread_mutex_lock()--Lock Mutex pthread_mutex_timedlock_np()--Lock Mutex with Time-Out pthread_mutex_unlock()--Unlock Mutex
Example
#include #include #include #include /* This example simulates a number of threads working on a parallel problem. The threads use pthread_mutex_trylock() so that <pthread.h> <stdio.h> <errno.h> "check.h"
they do not spend time blocking on a mutex and instead spend more of the time making progress towards the final solution. When trylock fails, the processing is done locally, eventually to be merged with the final parallel solution. This example should complete faster than the example for pthread_mutex_lock() in which threads solve the same parallel problem but spend more time waiting in resource contention. */ #define LOOPCONSTANT 100000 #define THREADS 10 pthread_mutex_t int mutex = PTHREAD_MUTEX_INITIALIZER; i,j,k,l;
void *threadfunc(void *parm) { int loop = 0; int localProcessingCompleted = 0; int numberOfLocalProcessingBursts = 0; int processingCompletedThisBurst = 0; int rc; for (loop=0; loop<LOOPCONSTANT; ++loop) { rc = pthread_mutex_trylock(&mutex); if (rc == EBUSY) { /* Process continue processing the part of the problem */ /* that we can without the lock. We do not want to waste */ /* time blocking. Instead, we'll count locally. */ ++localProcessingCompleted; ++numberOfLocalProcessingBursts; continue; } /* We acquired the lock, so this part of the can be global*/ checkResults("pthread_mutex_trylock()\n", rc); /* Processing completed consist of last local processing */ /* plus the 1 unit of processing this time through */ processingCompletedThisBurst = 1 + localProcessingCompleted; localProcessingCompleted = 0; i+=processingCompletedThisBurst; j+=processingCompletedThisBurst; k+=processingCompletedThisBurst; l+=processingCompletedThisBurst; rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc); } /* If any local processing remains, merge it with the global*/ /* problem so our part of the solution is accounted for */ if (localProcessingCompleted) { rc = pthread_mutex_lock(&mutex); checkResults("final pthread_mutex_lock()\n", rc); i+=localProcessingCompleted; j+=localProcessingCompleted; k+=localProcessingCompleted; l+=localProcessingCompleted; rc = pthread_mutex_unlock(&mutex); checkResults("final pthread_mutex_unlock()\n", rc); } printf("Thread processed about %d%% of the problem locally\n", (numberOfLocalProcessingBursts * 100) / LOOPCONSTANT); return NULL; }
int main(int argc, char **argv) { pthread_t threadid[THREADS]; int rc=0; int loop=0; pthread_attr_t pta; printf("Entering testcase\n"); pthread_attr_init(&pta); pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE); printf("Creating %d threads\n", THREADS); for (loop=0; loop<THREADS; ++loop) { rc = pthread_create(&threadid[loop], &pta, threadfunc, NULL); checkResults("pthread_create()\n", rc); } printf("Wait for results\n"); for (loop=0; loop<THREADS; ++loop) { rc = pthread_join(threadid[loop], NULL); checkResults("pthread_join()\n", rc); } printf("Cleanup and show results\n"); pthread_attr_destroy(&pta); pthread_mutex_destroy(&mutex); printf("\nUsing %d threads and LOOPCONSTANT = %d\n", THREADS, LOOPCONSTANT); printf("Values are: (should be %d)\n", THREADS * LOOPCONSTANT); printf(" ==>%d, %d, %d, %d\n", i, j, k, l); printf("Main completed\n"); return 0; }
Output:
Entering testcase Creating 10 threads Wait for results Thread processed about 100% of the problem locally Thread processed about 90% of the problem locally Thread processed about 88% of the problem locally Thread processed about 94% of the problem locally Thread processed about 93% of the problem locally Thread processed about 96% of the problem locally Thread processed about 90% of the problem locally Thread processed about 91% of the problem locally Thread processed about 81% of the problem locally Thread processed about 76% of the problem locally Cleanup and show results Using 10 threads and LOOPCONSTANT = 100000 Values are: (should be 1000000) ==>1000000, 1000000, 1000000, 1000000 Main completed
pthread_mutex_unlock()--Unlock Mutex
pthread_mutex_unlock()--Unlock Mutex
Syntax #include <pthread.h> int pthread_mutex_unlock(pthread_mutex_t *mutex); Threadsafe: Yes Signal Safe: Yes The pthread_mutex_unlock() function unlocks the mutex specified. If the calling thread does not currently hold the mutex (via a previous call to pthread_mutex_lock() or pthread_mutex_trylock()) the unlock request fails with the EPERM error. Mutex initialization using the PTHREAD_MUTEX_INITIALIZER does not immediately initialize the mutex. Instead, on first use, pthread_mutex_lock() or pthread_mutex_trylock() branches into a slow path and causes the initialization of the mutex. Because a mutex is not just a simple memory object and requires that some resources be allocated by the system, an attempt to call pthread_mutex_destroy() or pthread_mutex_unlock() on a mutex that was statically initialized using PTHREAD_MUTEX_INITIALER and was not yet locked causes an EINVAL error.
Mutex Types
A normal mutex cannot be locked repeatedly by the owner. Attempts by a thread to relock an already held mutex, or to lock a mutex that was held by another thread when that thread terminated, cause a deadlock condition. A recursive mutex can be locked repeatedly by the owner. The mutex does not become unlocked until the owner has called pthread_mutex_unlock() for each successful lock request that it has outstanding on the mutex. An errorcheck mutex checks for deadlock conditions that occur when a thread relocks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex is an OS/400 extension to the errorcheck mutex type. An ownerterm mutex checks for deadlock conditions that occur when a thread relocks an already held mutex. If a thread attempts to relock a mutex that it already holds, the lock request fails with the EDEADLK error. An ownerterm mutex also checks for deadlock conditions that occur when a thread attempts to lock a mutex that was held by another thread when that thread terminated (an orphaned mutex). If a thread attempts to lock an orphaned mutex, the lock request fails with the EOWNERTERM error. When a thread terminates the holding of a mutex lock on a normal or errorcheck mutex, other threads that wait for that mutex will block forever. The pthreads run-time simulates the deadlock that has occurred in your application. When you are attempting to debug these deadlock scenarios, the CL command WRKJOB, option 20, shows the thread as in a condition wait. Displaying the call stack shows that the function deadlockedOnOrphanedMutex is in the call stack. When a thread attempts to acquire a normal mutex that it already holds, the thread will block forever. The pthreads run-time simulates the deadlock that has occurred in your application. When you are attempting to debug these deadlock scenarios, the CL command WRKJOB, option 20, shows the thread as in a condition wait. Displaying the call stack shows that the function deadlockedOnAlreadyLockedMutex is in the call stack. To change these behaviors, use an errorcheck or ownerterm mutex type.
Parameters
mutex (Input) Address of the mutex to unlock
pthread_mutex_unlock()--Unlock Mutex
Return Value
0 pthread_mutex_unlock() was successful. value pthread_mutex_unlock() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_mutex_unlock() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EPERM] The mutex is not currently held by the caller
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_mutex_destroy()--Destroy Mutex pthread_mutex_init()--Initialize Mutex pthread_mutex_lock()--Lock Mutex pthread_mutex_trylock()--Lock Mutex with No Wait
Example
#include <pthread.h> #include <stdio.h> #include "check.h" pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int main(int argc, char **argv) { int rc=0; printf("Entering testcase\n"); printf("Lock the mutex\n"); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); /* All other threads will be blocked from the resource here */ printf("Unlock the mutex\n"); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc);
pthread_mutex_unlock()--Unlock Mutex
Output:
Entering testcase Lock the mutex Unlock the mutex Destroy the mutex Main completed
Parameters
None.
Return Value
0 pthread_lock_global_np() was successful. value pthread_lock_global_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_lock_global_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ERECURSE] The recursive mutex cannot be recursively locked again.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_unlock_global_np()--Unlock Global Mutex
Example
#include <pthread.h> #include <stdio.h> #include "check.h" /* This example shows the corruption that can result if no serialization is done and also shows the use of pthread_lock_global_np(). Call this test with no parameters to use pthread_lock_gloabl_np() to protect the critical data, between more than one (possibly unrelated) functions. Use 1 or more parameters to skip locking and show data corruption that occurs without locking. */ #define LOOPCONSTANT 50000 #define THREADS 10 int int i,j,k,l; uselock=1;
void secondFunction(void) { int rc; if (uselock) { rc = pthread_lock_global_np(); checkResults("pthread_lock_global_np()\n", rc); } --i; --j; --k; --l; if (uselock) { rc = pthread_unlock_global_np(); checkResults("pthread_unlock_global_np()\n", rc); } } void *threadfunc(void *parm) { int loop = 0; int rc; for (loop=0; loop<LOOPCONSTANT; ++loop) { if (uselock) { rc = pthread_lock_global_np(); checkResults("pthread_lock_global_np()\n", rc); } ++i; ++j; ++k; ++l; secondFunction(); ++i; ++j; ++k; ++l; if (uselock) { rc = pthread_unlock_global_np(); checkResults("pthread_unlock_global_np()\n", rc); } } return NULL; } int main(int argc, char **argv) { pthread_t threadid[THREADS]; int rc=0; int loop=0;
printf("Enter Testcase - %s\n", argv[0]); printf("Give any number of parameters to show data corruption\n"); if (argc != 1) { printf("A parameter was specified, no serialization is being done!\n"); uselock = 0; } if (uselock) { rc = pthread_lock_global_np(); checkResults("pthread_lock_global_np() (main)\n", rc); } printf("Creating %d threads\n", THREADS); for (loop=0; loop<THREADS; ++loop) { rc = pthread_create(&threadid[loop], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } sleep(5); if (uselock) { rc = pthread_unlock_global_np(); checkResults("pthread_unlock_global_np() (main)\n", rc); } printf("Wait for results\n"); for (loop=0; loop<THREADS; ++loop) { rc = pthread_join(threadid[loop], NULL); checkResults("pthread_join()\n", rc); } printf("\nUsing %d threads and LOOPCONSTANT = %d\n", THREADS, LOOPCONSTANT); printf("Values are: (should be %d)\n", THREADS * LOOPCONSTANT); printf(" ==>%d, %d, %d, %d\n", i, j, k, l); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPMTXGLB0 Give any number of parameters to show data corruption Creating 10 threads Wait for results Using 10 threads and LOOPCONSTANT = 50000 Values are: (should be 500000) ==>500000, 500000, 500000, 500000 Main completed
Parameters
None.
Return Value
0 pthread_unlock_global_np() was successful. value pthread_unlock_global_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_unlock_global_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EPERM] The mutex is not currently held by the caller.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_lock_global_np()--Lock Global Mutex
Example
See the pthread_lock_global_np() example.
For information about the examples included with the APIs, see the information on the API examples. To view the API list by description, see Condition variable synchronization APIs. Condition variable synchronization APIs list by name
q q q q q q q q q q q
pthread_condattr_destroy()--Destroy Condition Variable Attributes Object pthread_condattr_getpshared()--Get Process Shared Attribute from Condition Attributes Object pthread_condattr_init()--Initialize Condition Variable Attributes Object pthread_condattr_setpshared()--Set Process Shared Attribute in Condition Attributes Object pthread_cond_broadcast()--Broadcast Condition to All Waiting Threads pthread_cond_destroy()--Destroy Condition Variable pthread_cond_init()--Initialize Condition Variable pthread_cond_signal()--Signal Condition to One Waiting Thread pthread_cond_timedwait()--Timed Wait for Condition pthread_cond_wait()--Wait for Condition pthread_get_expiration_np()--Get Condition Expiration Time from Relative Time
Parameters
attr (Input) The address of the condition variable attributes object to be destroyed
Return Value
0 pthread_condattr_destroy() was successful. value pthread_condattr_destroy() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_condattr_destroy() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_condattr_init()--Initialize Condition Variable Attributes Object pthread_cond_init()--Initialize Condition Variable
Example
#include <pthread.h> #include <stdio.h> #include "check.h" pthread_cond_t cond;
int main(int argc, char **argv) { int rc=0; pthread_condattr_t attr; printf("Entering testcase\n"); printf("Create a default condition attribute\n"); rc = pthread_condattr_init(&attr); checkResults("pthread_condattr_init\n", rc); printf("Create the condition using the condition attributes object\n"); rc = pthread_cond_init(&cond, &attr); checkResults("pthread_cond_init()\n", rc); printf("- At this point, the condition with its default attributes\n"); printf("- Can be used from any threads that want to use it\n"); printf("Destroy cond attribute\n"); rc = pthread_condattr_destroy(&attr); checkResults("pthread_condattr_destroy()\n", rc); printf("Destroy condition\n"); rc = pthread_cond_destroy(&cond); checkResults("pthread_cond_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create a default condition attribute Create the condition using the condition attributes object - At this point, the condition with its default attributes - Can be used from any threads that want to use it Destroy cond attribute Destroy condition Main completed
Parameters
attr (Input) Address of the variable that contains the condition attributes object pshared (Output) Address of the variable to contain the pshared attribute result
Return Value
0 pthread_condattr_getpshared() was successful. value pthread_condattr_getpshared() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_condattr_getpshared() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_condattr_init()--Initialize Condition Variable Attributes Object
pthread_condattr_setpshared()--Set Process Shared Attribute in Condition Attributes Object pthread_cond_init()--Initialize Condition Variable
Example
See the example for pthread_condattr_setpshared().
Parameters
attr (Output) The address of the variable to contain the condition variable attributes object
Return Value
0 pthread_condattr_init() was successful. value pthread_condattr_init() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_condattr_init() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_condattr_destroy()--Destroy Condition Variable Attributes Object pthread_cond_init()--Initialize Condition Variable
Example
#include <pthread.h> #include <stdio.h> #include "check.h" pthread_cond_t cond;
int main(int argc, char **argv) { int rc=0; pthread_condattr_t attr; printf("Entering testcase\n"); printf("Create a default condition attribute\n"); rc = pthread_condattr_init(&attr); checkResults("pthread_condattr_init\n", rc); printf("Create the condition using the condition attributes object\n"); rc = pthread_cond_init(&cond, &attr); checkResults("pthread_cond_init()\n", rc); printf("- At this point, the condition with its default attributes\n"); printf("- Can be used from any threads that want to use it\n"); printf("Destroy cond attribute\n"); rc = pthread_condattr_destroy(&attr); checkResults("pthread_condattr_destroy()\n", rc); printf("Destroy condition\n"); rc = pthread_cond_destroy(&cond); checkResults("pthread_cond_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create a default condition attribute Create the condition using the condition attributes object - At this point, the condition with its default attributes - Can be used from any threads that want to use it Destroy cond attribute Destroy condition Main completed
Parameters
attr (Input) Address of the variable containing the condition attributes object pshared (Output) One of PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE
Return Value
0 pthread_condattr_setpshared() was successful. value pthread_condattr_setpshared() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_condattr_setpshared() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_condattr_getpshared()--Get Process Shared Attribute from Condition Attributes Object
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <spawn.h> #include <sys/wait.h> #include <unistd.h> #include <sys/shm.h> #include "check.h" typedef struct { int int int int pthread_cond_t pthread_mutex_t condition */ } shared_data_t; extern char shared_data_t pid_t int int eventOccured; numberWaiting; wokeup; reserved[1]; cond; mutex; /* Protects this shared data and
/* Change this path to be the path to where you create this example program */ #define MYPATH "/QSYS.LIB/QP0WTEST.LIB/TPCOSP0.PGM" #define NTHREADSTHISJOB #define NTHREADSTOTAL void void void void parentSetup(void); childSetup(void); parentCleanup(void); childCleanup(void); 2 4
void *parentThreadFunc(void *parm) { int rc; rc = pthread_mutex_lock(&sharedMem->mutex); checkResults("pthread_mutex_lock()\n", rc); /* Under protection of the lock, increment the count */ ++sharedMem->numberWaiting; while (!sharedMem->eventOccured) { printf("PARENT - Thread blocked\n"); rc = pthread_cond_wait(&sharedMem->cond, &sharedMem->mutex); checkResults("pthread_cond_wait()\n", rc); } printf("PARENT - Thread awake!\n");
/* Under protection of the lock, decrement the count */ --sharedMem->numberWaiting; /* After incrementing the wokeup flage and unlocking the mutex */ /* we no longer use the shared memory, the parent could destroy*/ /* it. We indicate we are finished with it using the wokeup flag*/ ++sharedMem->wokeup; rc = pthread_mutex_unlock(&sharedMem->mutex); checkResults("pthread_mutex_lock()\n", rc); return NULL; } void *childThreadFunc(void *parm) { int rc; rc = pthread_mutex_lock(&sharedMem->mutex); checkResults("pthread_mutex_lock()\n", rc); /* Under protection of the lock, increment the count */ ++sharedMem->numberWaiting; while (!sharedMem->eventOccured) { printf("CHILD - Thread blocked\n"); rc = pthread_cond_wait(&sharedMem->cond, &sharedMem->mutex); checkResults("pthread_cond_wait()\n", rc); } printf("CHILD - Thread awake!\n"); /* Under protection of the lock, decrement the count */ --sharedMem->numberWaiting; /* After incrementing the wokeup flage and unlocking the mutex */ /* we no longer use the shared memory, the parent could destroy*/ /* it. We indicate we are finished with it using the wokeup flag*/ ++sharedMem->wokeup; rc = pthread_mutex_unlock(&sharedMem->mutex); checkResults("pthread_mutex_lock()\n", rc); return NULL; } int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid[NTHREADSTHISJOB]; int parentJob=0; /* If we run this from the QSHELL interpreter on the AS/400, we want */ /* it to be line buffered even if we run it in batch so the output between*/ /* parent and child is intermixed. */ setvbuf(stdout,NULL,_IOLBF,4096); /* Determine if we are running in the parent or child */ if (argc != 1 && argc != 2) { printf("Incorrect usage\n"); printf("Pass no parameters to run as the parent testcase\n"); printf("Pass one parameter `ASCHILD' to run as the child testcase\n"); exit(1); }
if (argc == 1) { parentJob = 1; } else { if (strcmp(argv[1], "ASCHILD")) { printf("Incorrect usage\n"); printf("Pass no parameters to run as the parent testcase\n"); printf("Pass one parameter `ASCHILD' to run as the child testcase\n"); exit(1); } parentJob = 0; } /* PARENT *****************************************************************/ if (parentJob) { printf("PARENT - Enter Testcase - %s\n", argv[0]); parentSetup(); printf("PARENT - Create %d threads\n", NTHREADSTHISJOB); for (i=0; i<NTHREADSTHISJOB; ++i) { rc = pthread_create(&threadid[i], NULL, parentThreadFunc, NULL); checkResults("pthread_create()\n", rc); } rc = pthread_mutex_lock(&sharedMem->mutex); checkResults("pthread_mutex_lock()\n", rc); while (sharedMem->numberWaiting != NTHREADSTOTAL) { printf("PARENT - Waiting for %d threads to wait, " "currently %d waiting\n", NTHREADSTOTAL, sharedMem->numberWaiting); rc = pthread_mutex_unlock(&sharedMem->mutex); checkResults("pthread_mutex_unlock()\n", rc); sleep(1); rc = pthread_mutex_lock(&sharedMem->mutex); checkResults("pthread_mutex_lock()\n", rc); } printf("PARENT - wake up all of the waiting threads...\n"); sharedMem->eventOccured = 1; rc = pthread_cond_broadcast(&sharedMem->cond); checkResults("pthread_cond_signal()\n", rc); printf("PARENT - Wait for waking threads and cleanup\n"); while (sharedMem->wokeup != NTHREADSTOTAL) { printf("PARENT - Waiting for %d threads to wake, " "currently %d wokeup\n", NTHREADSTOTAL, sharedMem->wokeup); rc = pthread_mutex_unlock(&sharedMem->mutex); checkResults("pthread_mutex_unlock()\n", rc); sleep(1); rc = pthread_mutex_lock(&sharedMem->mutex); checkResults("pthread_mutex_lock()\n", rc); } parentCleanup(); printf("PARENT - Main completed\n");
exit(0); } /* CHILD *****************************************************************/ { void *status=NULL; printf("CHILD - Enter Testcase - %s\n", argv[0]); childSetup(); printf("CHILD - Create %d threads\n", NTHREADSTHISJOB); for (i=0; i<NTHREADSTHISJOB; ++i) { rc = pthread_create(&threadid[i], NULL, childThreadFunc, NULL); checkResults("pthread_create()\n", rc); } /* The parent will wake up all of these threads using the */ /* pshared condition variable. We will just join to them... */ printf("CHILD - Joining to all threads\n"); for (i=0; i<NTHREADSTHISJOB; ++i) { rc = pthread_join(threadid[i], &status); checkResults("pthread_join()\n", rc); if (status != NULL) { printf("CHILD - Got a bad status from a thread, " "%.8x %.8x %.8x %.8x\n", status); exit(1); } } /* After all the threads are awake, the parent will destroy */ /* the condition and mutex. Do not use it anymore */ childCleanup(); printf("CHILD - Main completed\n"); } return 0; } /***************************************************************/ /* This function initializes the shared memory for the job, */ /* sets up the environment variable indicating where the shared*/ /* memory is, and spawns the child job. */ /* */ /* It creates and initializes the shared memory segment, and */ /* It initializes the following global variables in this */ /* job. */ /* sharedMem */ /* childPid */ /* shmid */ /* */ /* If any of this setup/initialization fails, it will exit(1) */ /* and terminate the test. */ /* */ /***************************************************************/ void parentSetup(void) { int rc; /***************************************************************/ /* Create shared memory for shared_data_t above */ /* attach the shared memory */
/* set the static/global sharedMem pointer to it */ /***************************************************************/ printf("PARENT - Create the shared memory segment\n"); rc = shmget(IPC_PRIVATE, sizeof(shared_data_t), 0666); if (rc == -1) { printf("PARENT - Failed to create a shared memory segment\n"); exit(1); } shmid = rc; printf("PARENT - Attach the shared memory\n"); sharedMem = shmat(shmid, NULL, 0); if (sharedMem == NULL) { shmctl(shmid, IPC_RMID, NULL); printf("PARENT - Failed to attach shared memory\n"); exit(1); } /***************************************************************/ /* Initialize the mutex/condition and other shared memory data */ /***************************************************************/ { pthread_mutexattr_t mattr; pthread_condattr_t cattr; printf("PARENT - Init shared memory mutex/cond\n"); memset(sharedMem, 0, sizeof(shared_data_t)); /* Process Shared Mutex */ rc = pthread_mutexattr_init(&mattr); checkResults("pthread_mutexattr_init()\n", rc); rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); checkResults("pthread_mutexattr_setpshared()\n", rc); rc = pthread_mutex_init(&sharedMem->mutex, &mattr); checkResults("pthread_mutex_init()\n", rc); /* Process Shared Condition */ rc = pthread_condattr_init(&cattr); checkResults("pthread_condattr_init()\n", rc); rc = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED); checkResults("pthread_condattr_setpshared()\n", rc); rc = pthread_cond_init(&sharedMem->cond, &cattr); checkResults("pthread_cond_init()\n", rc); } /**************************************************************/ /* Set and environment variable so that the child can inherit */ /* it and know the shared memory ID */ /**************************************************************/ { char shmIdEnvVar[128]; sprintf(shmIdEnvVar, "TPCOSP0_SHMID=%d\n", shmid); rc = putenv(shmIdEnvVar); if (rc) { printf("PARENT - Failed to store env var %s, errno=%d\n", shmIdEnvVar, errno); exit(1); } printf("PARENT - Stored shared memory id of %d\n", shmid);
} /**************************************************/ /* Spawn the child job */ /**************************************************/ { inheritance_t in; char *av[3] = {NULL, NULL, NULL}; /* Allow thread creation in the spawned child memset(&in, 0, sizeof(in)); in.flags = SPAWN_SETTHREAD_NP; /* Set up the arguments to pass to spawn based on the /* arguments passed in av[0] = MYPATH; av[1] = "ASCHILD"; av[2] = NULL; */
*/ */
/* Spawn the child that was specified, inheriting all */ /* of the environment variables. */ childPid = spawn(MYPATH, 0, NULL, &in, av, environ); if (childPid == -1) { /* spawn failure */ printf("PARENT - spawn() failed, errno=%d\n", errno); exit(1); } printf("PARENT - spawn() success, [PID=%d]\n", childPid); } return; } /***************************************************************/ /* This function attaches the shared memory for the child job, */ /* It uses the environment variable indicating where the shared*/ /* memory is. */ /* */ /* If any of this setup/initialization fails, it will exit(1) */ /* and terminate the test. */ /* */ /* It initializes the following global variables: */ /* sharedMem */ /* shmid */ /***************************************************************/ void childSetup(void) { int rc; printf("CHILD - Child setup\n"); /**************************************************************/ /* Set and environment variable so that the child can inherit */ /* it and know the shared memory ID */ /**************************************************************/ { char *shmIdEnvVar; shmIdEnvVar = getenv("TPCOSP0_SHMID"); if (shmIdEnvVar == NULL) { printf("CHILD - Failed to get env var \"TPCOSP0_SHMID\", errno=%d\n",
errno); exit(1); } shmid = atoi(shmIdEnvVar); printf("CHILD - Got shared memory id of %d\n", shmid); } /***************************************************************/ /* Create shared memory for shared_data_t above */ /* attach the shared memory */ /* set the static/global sharedMem pointer to it */ /***************************************************************/ printf("CHILD - Attach the shared memory\n"); sharedMem = shmat(shmid, NULL, 0); if (sharedMem == NULL) { shmctl(shmid, IPC_RMID, NULL); printf("CHILD - Failed to attach shared memory\n"); exit(1); } return; } /***************************************************************/ /* wait for child to complete and get return code. */ /* Destroy mutex and condition in shared memory */ /* detach and remove shared memory */ /* set the child's return code in global storage */ /* */ /* If this function fails, it will call exit(1) */ /* */ /* This function sets the following global variables: */ /* sharedMem */ /* childStatus */ /* shmid */ /***************************************************************/ void parentCleanup(void) { int status=0; int rc; int waitedPid=0; /* Even though there is no thread left in the child using the /* contents of the shared memory, before we destroy the mutex /* and condition in that shared memory, we will wait for the /* child job to complete, we know for 100% certainty that no /* threads in the child are using it then. printf("PARENT - Parent cleanup\n"); /* Wait for the child to complete */ waitedPid = waitpid(childPid,&status,0); if (rc == -1) { printf("PARENT - waitpid failed, errno=%d\n", errno); exit(1); } childStatus = status; /* Cleanup resources */ rc = pthread_mutex_destroy(&sharedMem->mutex); checkResults("pthread_mutex_destroy()\n", rc); rc = pthread_cond_destroy(&sharedMem->cond); checkResults("pthread_cond_destroy()\n", rc); */ */ */ */ */
/* Detach/Remove shared memory */ rc = shmdt(sharedMem); if (rc) { printf("PARENT - Failed to detach shared memory, errno=%d\n", errno); exit(1); } rc = shmctl(shmid, IPC_RMID, NULL); if (rc) { printf("PARENT - Failed to remove shared memory id=%d, errno=%d\n", shmid, errno); exit(1); } shmid = 0; return; } /***************************************************************/ /* Detach the shared memory */ /* At this point, there is no serialization, so the contents */ /* of the shared memory should not be used. */ /* */ /* If this function fails, it will call exit(1) */ /* */ /* This function sets the following global variables: */ /* sharedMem */ /***************************************************************/ void childCleanup(void) { int rc; printf("CHILD - Child cleanup\n"); rc = shmdt(sharedMem);
sharedMem = NULL; if (rc) { printf("CHILD - Failed to detach shared memory, errno=%d\n", errno); exit(1); } return; }
Output:
This example was run under the OS/400 QShell Interpreter. In the QShell Interpreter, a program gets descriptors 0, 1, and 2 as the standard files; the parent and child I/O is directed to the console. When run in the QShell Interpreter, the output shows the intermixed output from both parent and child processes and gives a feeling for the time sequence of operations occurring in each job. The QShell interpreter allows you to run multithreaded programs as if they were interactive. See the QShell documentation for a description of the QIBM_MULTI_THREADED shell variable, which allows you to start multithreaded programs. The QShell Interpreter is option 30 of Base OS/400. .
PARENT - Create the shared memory segment PARENT - Attach the shared memory PARENT - Init shared memory mutex/cond PARENT - Stored shared memory id of 862 PARENT - spawn() success, [PID=2651] PARENT - Create 2 threads PARENT - Thread blocked PARENT - Waiting for 4 threads to wait, currently 1 waiting PARENT - Thread blocked CHILD - Enter Testcase - QP0WTEST/TPCOSP0 CHILD - Child setup CHILD - Got shared memory id of 862 CHILD - Attach the shared memory CHILD - Create 2 threads CHILD - Thread blocked CHILD - Joining to all threads CHILD - Thread blocked PARENT - wake up all of the waiting threads... PARENT - Wait for waking threads and cleanup PARENT - Waiting for 4 threads to wake, currently 0 wokeup PARENT - Thread awake! CHILD - Thread awake! PARENT - Thread awake! CHILD - Thread awake! CHILD - Child cleanup CHILD - Main completed PARENT - Parent cleanup PARENT - Main completed
Parameters
cond (Input) Pointer to the condition variable that is to be broadcast to
Return Value
0 pthread_cond_broadcast() was successful. value pthread_cond_broadcast() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_cond_broadcast() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cond_init()--Initialize Condition Variable pthread_cond_signal()--Signal Condition to One Waiting Thread
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" /* For safe condition variable usage, must use a boolean predicate and /* a mutex with the condition. int conditionMet = 0; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #define NTHREADS 5 */ */
void *threadfunc(void *parm) { int rc; rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); while (!conditionMet) { printf("Thread blocked\n"); rc = pthread_cond_wait(&cond, &mutex); checkResults("pthread_cond_wait()\n", rc); } rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_lock()\n", rc); return NULL; } int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid[NTHREADS]; printf("Enter Testcase - %s\n", argv[0]); printf("Create %d threads\n", NTHREADS); for(i=0; i<NTHREADS; ++i) { rc = pthread_create(&threadid[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } sleep(5); /* Sleep is not a very robust way to serialize threads */ rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); /* The condition has occured. Set the flag and wake up any waiting threads */ conditionMet = 1; printf("Wake up all waiting threads...\n"); rc = pthread_cond_broadcast(&cond);
checkResults("pthread_cond_broadcast()\n", rc); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc); printf("Wait for threads and cleanup\n"); for (i=0; i<NTHREADS; ++i) { rc = pthread_join(threadid[i], NULL); checkResults("pthread_join()\n", rc); } pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create 5 threads Thread blocked Thread blocked Thread blocked Thread blocked Thread blocked Wake up all waiting threads... Wait for threads and cleanup Main completed
Parameters
cond (Input) Address of the condition variable to destroy
Return Value
0 pthread_cond_destroy() was successful. value pthread_cond_destroy() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_cond_destroy() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EBUSY] The condition variable was in use.
Related Information
q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cond_broadcast()--Broadcast Condition to All Waiting Threads pthread_cond_init()--Initialize Condition Variable pthread_cond_signal()--Signal Condition to One Waiting Thread pthread_cond_timedwait()--Timed Wait for Condition pthread_cond_wait()--Wait for Condition
Example
#include <pthread.h> #include <stdio.h> #include "check.h" pthread_cond_t cond;
int main(int argc, char **argv) { int rc=0; pthread_mutexattr_t attr; printf("Entering testcase\n"); printf("Create the condition using the condition attributes object\n"); rc = pthread_cond_init(&cond, NULL); checkResults("pthread_cond_init()\n", rc); printf("- At this point, the condition with its default attributes\n"); printf("- Can be used from any threads that want to use it\n"); printf("Destroy condition\n"); rc = pthread_cond_destroy(&cond); checkResults("pthread_cond_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create the condition using the condition attributes object - At this point, the condition with its default attributes - Can be used from any threads that want to use it Destroy condition Main completed
Parameters
cond (Output) The address of the condition variable to initialize attr (Input) The address of the condition attributes object to use for initialization
Return Value
0 pthread_cond_init() was successful. value pthread_cond_init() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_cond_init() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cond_broadcast()--Broadcast Condition to All Waiting Threads pthread_cond_destroy()--Destroy Condition Variable pthread_cond_signal()--Signal Condition to One Waiting Thread pthread_cond_timedwait()--Timed Wait for Condition pthread_cond_wait()--Wait for Condition
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_cond_t pthread_cond_t pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; cond2; cond3;
int main(int argc, char **argv) { int rc=0; pthread_condattr_t attr; printf("Enter Testcase - %s\n", argv[0]); printf("Create the default cond attributes object\n"); rc = pthread_condattr_init(&attr); checkResults("pthread_condattr_init()\n", rc); printf("Create the all of the default conditions in different ways\n"); rc = pthread_cond_init(&cond2, NULL); checkResults("pthread_cond_init()\n", rc); rc = pthread_cond_init(&cond3, &attr); checkResults("pthread_cond_init()\n", rc); printf("- At this point, the conditions with default attributes\n");
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_75.htm (2 of 3) [2/9/2001 2:03:36 PM]
printf("- Can be used from any threads that want to use them\n"); printf("Cleanup\n"); pthread_condattr_destroy(&attr); pthread_cond_destroy(&cond1); pthread_cond_destroy(&cond2); pthread_cond_destroy(&cond3); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPCOI0 Create the default cond attributes object Create the all of the default conditions in different ways - At this point, the conditions with default attributes - Can be used from any threads that want to use them Cleanup Main completed
Parameters
cond (Input) Address of the condition variable to be signaled
Return Value
0 pthread_cond_signal() was successful. value pthread_cond_signal() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_cond_signal() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The condition specified is not valid.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cond_broadcast()--Broadcast Condition to All Waiting Threads pthread_cond_init()--Initialize Condition Variable
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" /* For safe condition variable usage, must use a boolean predicate and /* a mutex with the condition. int workToDo = 0; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #define NTHREADS 2 */ */
void *threadfunc(void *parm) { int rc; while (1) { /* Usually worker threads will loop on these operations */ rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); while (!workToDo) { printf("Thread blocked\n"); rc = pthread_cond_wait(&cond, &mutex); checkResults("pthread_cond_wait()\n", rc); } printf("Thread awake, finish work!\n"); /* Under protection of the lock, complete or remove the work /* from whatever worker queue we have. Here it is simply a flag workToDo = 0; rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_lock()\n", rc); } return NULL; } int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid[NTHREADS]; printf("Enter Testcase - %s\n", argv[0]); printf("Create %d threads\n", NTHREADS); for(i=0; i<NTHREADS; ++i) { rc = pthread_create(&threadid[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } sleep(5); /* Sleep is not a very robust way to serialize threads */ */ */
for(i=0; i<5; ++i) { printf("Wake up a worker, work to do...\n"); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); /* /* /* /* if In the real world, all the threads might be busy, and we would add work to a queue instead of simply using a flag In that case the boolean predicate might be some boolean statement like: if (the-queue-contains-work) (workToDo) { printf("Work already present, likely threads are busy\n"); */ */ */ */
} workToDo = 1; rc = pthread_cond_signal(&cond); checkResults("pthread_cond_broadcast()\n", rc); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc); sleep(5); /* Sleep is not a very robust way to serialize threads */ } printf("Main completed\n"); exit(0); return 0; }
Output:
Enter Testcase - QP0WTEST/TPCOS0 Create 2 threads Thread blocked Thread blocked Wake up a worker, work to do... Thread awake, finish work! Thread blocked Wake up a worker, work to do... Thread awake, finish work! Thread blocked Wake up a worker, work to do... Thread awake, finish work! Thread blocked Wake up a worker, work to do... Thread awake, finish work! Thread blocked Wake up a worker, work to do... Thread awake, finish work! Thread blocked Main completed
Parameters
cond (Input) Address of the condition variable to wait for mutex (Input) Address of the locked mutex associated with the condition variable abstime (Input) Address of the absolute system time at which the wait expires
Return Value
0 pthread_cond_timedwait() was successful. value pthread_cond_timedwait() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_cond_timedwait() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ENOTLOCKED] The mutex specified is not locked by the caller. [ETIMEDOUT] The wait timed out without being satisfied.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cond_broadcast()--Broadcast Condition to All Waiting Threads pthread_cond_init()--Initialize Condition Variable pthread_cond_signal()--Signal Condition to One Waiting Threads pthread_cond_wait()--Wait for Condition
Example
#define _MULTI_THREADED #include <stdio.h> #include <qp0z1170.h> #include <time.h> #include <pthread.h> #include "check.h" /* For safe condition variable usage, must use a boolean predicate and /* a mutex with the condition. int workToDo = 0; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #define NTHREADS #define WAIT_TIME_SECONDS void *threadfunc(void *parm) {
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_77.htm (2 of 4) [2/9/2001 2:03:37 PM]
*/ */
3 15
rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); /* Usually worker threads will loop on these operations */ while (1) { rc = gettimeofday(&tp, NULL); checkResults("gettimeofday()\n", rc); /* Convert from timeval to timespec */ ts.tv_sec = tp.tv_sec; ts.tv_nsec = tp.tv_usec * 1000; ts.tv_sec += WAIT_TIME_SECONDS; while (!workToDo) { printf("Thread blocked\n"); rc = pthread_cond_timedwait(&cond, &mutex, &ts); /* If the wait timed out, in this example, the work is complete, and */ /* the thread will end. */ /* In reality, a timeout must be accompanied by some sort of checking */ /* to see if the work is REALLY all complete. In the simple example */ out. /* we will just go belly up when we time */ if (rc == ETIMEDOUT) { printf("Wait timed out!\n"); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_lock()\n", rc); pthread_exit(NULL); } checkResults("pthread_cond_timedwait()\n", rc); } printf("Thread consumes work here\n"); workToDo = 0; } rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_lock()\n", rc); return NULL; } int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid[NTHREADS]; printf("Enter Testcase - %s\n", argv[0]); printf("Create %d threads\n", NTHREADS); for(i=0; i<NTHREADS; ++i) { rc = pthread_create(&threadid[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); }
rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); printf("One work item to give to a thread\n"); workToDo = 1; rc = pthread_cond_signal(&cond); checkResults("pthread_cond_signal()\n", rc); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc); printf("Wait for threads and cleanup\n"); for (i=0; i<NTHREADS; ++i) { rc = pthread_join(threadid[i], NULL); checkResults("pthread_join()\n", rc); } pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPCOT0 Create 3 threads Thread blocked One work item to give to a thread Wait for threads and cleanup Thread consumes work here Thread blocked Thread blocked Thread blocked Wait timed out! Wait timed out! Wait timed out! Main completed
Parameters
cond (Input) Address of the condition variable to wait on mutex (Input) Address of the mutex associated with the condition variable
Return Value
0 pthread_cond_wait() was successful. value pthread_cond_wait() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_cond_wait() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
[ENOTLOCKED] The mutex associated with the condition variable is not locked.
Related Information
q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cond_broadcast()--Broadcast Condition to All Waiting Threads pthread_cond_init()--Initialize Condition Variable pthread_cond_signal()--Signal Condition to One Waiting Thread pthread_cond_timedwait()--Timed Wait for Condition
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" /* For safe condition variable usage, must use a boolean predicate and /* a mutex with the condition. int conditionMet = 0; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #define NTHREADS 5 */ */
void *threadfunc(void *parm) { int rc; rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); while (!conditionMet) { printf("Thread blocked\n"); rc = pthread_cond_wait(&cond, &mutex); checkResults("pthread_cond_wait()\n", rc); } rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_lock()\n", rc); return NULL; } int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid[NTHREADS]; printf("Enter Testcase - %s\n", argv[0]); printf("Create %d threads\n", NTHREADS); for(i=0; i<NTHREADS; ++i) { rc = pthread_create(&threadid[i], NULL, threadfunc, NULL);
checkResults("pthread_create()\n", rc); } sleep(5); /* Sleep is not a very robust way to serialize threads */ rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); /* The condition has occured. Set the flag and wake up any waiting threads */ conditionMet = 1; printf("Wake up all waiting threads...\n"); rc = pthread_cond_broadcast(&cond); checkResults("pthread_cond_broadcast()\n", rc); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_unlock()\n", rc); printf("Wait for threads and cleanup\n"); for (i=0; i<NTHREADS; ++i) { rc = pthread_join(threadid[i], NULL); checkResults("pthread_join()\n", rc); } pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex); printf("Main completed\n"); return 0; }
Output:
Entering testcase Create 5 threads Thread blocked Thread blocked Thread blocked Thread blocked Thread blocked Wake up all waiting threads... Wait for threads and cleanup Main completed
Parameters
delta (Input) Elapsed time to add to the current system time abstime (Output) Address of the returned value representing the expiration time
Return Value
0 pthread_get_expiration_np() was successful. value pthread_get_expiration_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_get_expiration_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cond_timedwait()--Timed Wait for Condition
Example
#define _MULTI_THREADED #include <stdio.h> #include <qp0z1170.h> #include <time.h> #include <pthread.h> #include "check.h" /* For safe condition variable usage, must use a boolean predicate and /* a mutex with the condition. int workToDo = 0; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int failStatus=99; #define NTHREADS #define WAIT_TIME_SECONDS void *threadfunc(void *parm) { int rc; struct timespec delta; struct timespec abstime; int retries = 2; pthread_id_np_t tid; tid = pthread_getthreadid_np(); rc = pthread_mutex_lock(&mutex); checkResults("pthread_mutex_lock()\n", rc); while (retries--) { delta.tv_sec = WAIT_TIME_SECONDS; delta.tv_nsec = 0; rc = pthread_get_expiration_np(&delta, &abstime); checkResults("pthread_get_expiration_np()\n", rc); while (!workToDo) { printf("Thread 0x%.8x %.8x blocked\n", tid); rc = pthread_cond_timedwait(&cond, &mutex, &abstime); if (rc != ETIMEDOUT) { printf("pthread_cond_timedwait() - expect timeout %d\n", rc); rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_lock()\n", rc); return __VOID(failStatus); } /* Since there is no code in this example to wake up any */ /* thread on the condition variable, we know we are done */ /* because we have timed out. */ break; } printf("Wait timed out! tid=0x%.8x %.8x\n", tid); } rc = pthread_mutex_unlock(&mutex); checkResults("pthread_mutex_lock()\n", rc); return __VOID(0); } 2 3 */ */
int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid[NTHREADS]; void *status; int results=0; printf("Enter Testcase - %s\n", argv[0]); printf("Create %d threads\n", NTHREADS); for(i=0; i<NTHREADS; ++i) { rc = pthread_create(&threadid[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } printf("Wait for threads and cleanup\n"); for (i=0; i<NTHREADS; ++i) { rc = pthread_join(threadid[i], &status); checkResults("pthread_join()\n", rc); if (__INT(status) == failStatus) { printf("A thread failed!\n"); results++; } } pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex); printf("Main completed\n"); return results; }
Output:
Enter Testcase - QP0WTEST/TPGETEX0 Create 2 threads Wait for threads and cleanup Thread 0x00000000 000002ab blocked Thread 0x00000000 000002ac blocked Wait timed out! tid=0x00000000 000002ab Thread 0x00000000 000002ab blocked Wait timed out! tid=0x00000000 000002ac Thread 0x00000000 000002ac blocked Wait timed out! tid=0x00000000 000002ab Wait timed out! tid=0x00000000 000002ac Main completed
For information about the examples included with the APIs, see the information on the API examples. To view the API list by description, see Read/write lock synchronization APIs. Read/write lock synchronization APIs by name
q q q q q q q q q q q q q
pthread_rwlockattr_destroy()--Destroy Read/Write Lock Attribute pthread_rwlockattr_getpshared()--Get Pshared Read/Write Lock Attribute pthread_rwlockattr_init()--Initialize Read/Write Lock Attribute pthread_rwlockattr_setpshared()--Set Pshared Read/Write Lock Attribute pthread_rwlock_destroy()--Destroy Read/Write Lock pthread_rwlock_init()--Initialize Read/Write Lock pthread_rwlock_rdlock()--Get Shared Read Lock pthread_rwlock_timedrdlock_np()--Get Shared Read Lock with Time-Out pthread_rwlock_timedwrlock_np()--Get Exclusive Write Lock with Time-Out pthread_rwlock_tryrdlock()--Get Shared Read Lock with No Wait pthread_rwlock_trywrlock()--Get Exclusive Write Lock with No Wait pthread_rwlock_unlock()--Unlock Exclusive Write or Shared Read Lock pthread_rwlock_wrlock()--Get Exclusive Write Lock
Parameters
attr (Input) Address of the read/write lock attributes object to be destroyed
Return Value
0 pthread_rwlockattr_destroy() was successful. value pthread_rwlockattr_destroy() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlockattr_destroy() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlockattr_init()--Initialize Read/Write Lock Attribute pthread_rwlock_init()--Initialize Read/Write Lock
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h"
pthread_rwlock_t pthread_rwlock_t
int main(int argc, char **argv) { int rc=0; pthread_rwlockattr_t attr; printf("Enter Testcase - %s\n", argv[0]); printf("Create a default rwlock attribute\n"); rc = pthread_rwlockattr_init(&attr); checkResults("pthread_rwlockattr_init()\n", rc); printf("Use the rwlock attributes to created rwlocks here\n"); rc = pthread_rwlock_init(&rwlock1, &attr); checkResults("pthread_rwlock_init()\n", rc); printf("The rwlock1 is now ready for use.\n"); printf("The rwlock2 that was statically initialized was ready when\n" "the main routine was entered\n"); printf("Destroy rwlock attribute\n"); rc = pthread_rwlockattr_destroy(&attr); checkResults("pthread_rwlockattr_destroy()\n", rc); printf("Use the rwlocks\n"); rc = pthread_rwlock_rdlock(&rwlock1); checkResults("pthread_rwlock_rdlock()\n", rc); rc = pthread_rwlock_wrlock(&rwlock2); checkResults("pthread_rwlock_wrlock()\n", rc); rc = pthread_rwlock_unlock(&rwlock1); checkResults("pthread_rwlock_unlock(1)\n", rc); rc = pthread_rwlock_unlock(&rwlock2); checkResults("pthread_rwlock_unlock(2)\n", rc); printf("Destroy the rwlocks\n"); rc = pthread_rwlock_destroy(&rwlock1); checkResults("pthread_rwlock_destroy(1)\n", rc); rc = pthread_rwlock_destroy(&rwlock2); checkResults("pthread_rwlock_destroy(2)\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPRWLAI0 Create a default rwlock attribute Use the rwlock attributes to created rwlocks here The rwlock is now ready for use. The rwlock that was statically initialized was ready when the main routine was entered Destroy rwlock attribute Use the rwlocks
Parameters
attr (Input) Address of the variable that contains the read/write lock attributes object attr (Output) Address of the variable to contain the pshared attribute result
Return Value
0 pthread_rwlockattr_getpshared() was successful. value pthread_rwlockattr_getpshared() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlockattr_getpshared() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlockattr_init()--Initialize Read/Write Lock Attribute
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <spawn.h> #include <sys/wait.h> #include <unistd.h> #include <sys/shm.h> #include "check.h" typedef struct { int pthread_rwlock_t } shared_data_t; extern char shared_data_t pid_t int int protectedResource; rwlock;
/* Change this path to be the path to where you create this example program */ #define MYPATH "/QSYS.LIB/QP0WTEST.LIB/TPRWLSH0.PGM" #define NTHREADSTHISJOB #define NTHREADSTOTAL void void void void parentSetup(void); childSetup(void); parentCleanup(void); childCleanup(void); 2 4
void *childReaderThreadFunc(void *parm) { int rc; int retries = 5; while (retries--) { rc = pthread_rwlock_rdlock(&sharedMem->rwlock); checkResults("pthread_rwlock_rdlock()\n", rc); /* Under protection of the shared read lock, read the resource */ printf("CHILD READER - current protectedResource = %d\n", sharedMem->protectedResource); sleep(1); printf("CHILD READER - unlock\n"); rc = pthread_rwlock_unlock(&sharedMem->rwlock); checkResults("pthread_rwlock_unlock()\n", rc); } return NULL; } void *parentWriterThreadFunc(void *parm) {
int
rc;
rc = pthread_rwlock_wrlock(&sharedMem->rwlock); checkResults("pthread_rwlock_rdlock()\n", rc); /* Under protection of the exclusive write lock, write the resource */ ++sharedMem->protectedResource; printf("PARENT WRITER - current protectedResource = %d\n", sharedMem->protectedResource); sleep(5); printf("PARENT WRITER - unlock\n"); rc = pthread_rwlock_unlock(&sharedMem->rwlock);
checkResults("pthread_rwlock_unlock()\n", rc); return NULL; } int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid[NTHREADSTHISJOB]; int parentJob=0; void *status=NULL; /* If we run this from the QSHELL interpreter on the AS/400, we want */ /* it to be line buffered even if we run it in batch so the output between*/ /* parent and child is intermixed. */ setvbuf(stdout,NULL,_IOLBF,4096); /* Determine if we are running in the parent or child */ if (argc != 1 && argc != 2) { printf("Incorrect usage\n"); printf("Pass no parameters to run as the parent testcase\n"); printf("Pass one parameter `ASCHILD' to run as the child testcase\n"); exit(1); } if (argc == 1) { parentJob = 1; } else { if (strcmp(argv[1], "ASCHILD")) { printf("Incorrect usage\n"); printf("Pass no parameters to run as the parent testcase\n"); printf("Pass one parameter `ASCHILD' to run as the child testcase\n"); exit(1); } parentJob = 0; } /* PARENT *****************************************************************/ if (parentJob) {
printf("PARENT - Enter Testcase - %s\n", argv[0]); parentSetup(); printf("PARENT - Create %d threads\n", NTHREADSTHISJOB); for (i=0; i<NTHREADSTHISJOB; ++i) { rc = pthread_create(&threadid[i], NULL, parentWriterThreadFunc, NULL); checkResults("pthread_create()\n", rc); } for (i=0; i<NTHREADSTHISJOB; ++i) { rc = pthread_join(threadid[i], NULL); checkResults("pthread_create()\n", rc); if (status != NULL) { printf("PARENT - Got a bad status from a thread, " "%.8x %.8x %.8x %.8x\n", status); exit(1); } } parentCleanup(); printf("PARENT - Main completed\n"); exit(0); } /* CHILD *****************************************************************/ { printf("CHILD - Enter Testcase - %s\n", argv[0]); childSetup(); printf("CHILD - Create %d threads\n", NTHREADSTHISJOB); for (i=0; i<NTHREADSTHISJOB; ++i) { rc = pthread_create(&threadid[i], NULL, childReaderThreadFunc, NULL); checkResults("pthread_create()\n", rc); } /* The parent will wake up all of these threads using the */ /* pshared condition variable. We will just join to them... */ printf("CHILD - Joining to all threads\n"); for (i=0; i<NTHREADSTHISJOB; ++i) { rc = pthread_join(threadid[i], &status); checkResults("pthread_join()\n", rc); if (status != NULL) { printf("CHILD - Got a bad status from a thread, " "%.8x %.8x %.8x %.8x\n", status); exit(1); } } /* After all the threads are awake, the parent will destroy */ /* the read/write lock. Do not use it anymore */ childCleanup(); printf("CHILD - Main completed\n"); } return 0; } /***************************************************************/ /* This function initializes the shared memory for the job, */
/* sets up the environment variable indicating where the shared*/ /* memory is, and spawns the child job. */ /* */ /* It creates and initializes the shared memory segment, and */ /* It initializes the following global variables in this */ /* job. */ /* sharedMem */ /* childPid */ /* shmid */ /* */ /* If any of this setup/initialization fails, it will exit(1) */ /* and terminate the test. */ /* */ /***************************************************************/ void parentSetup(void) { int rc; /***************************************************************/ /* Create shared memory for shared_data_t above */ /* attach the shared memory */ /* set the static/global sharedMem pointer to it */ /***************************************************************/ printf("PARENT - Create the shared memory segment\n"); rc = shmget(IPC_PRIVATE, sizeof(shared_data_t), 0666); if (rc == -1) { printf("PARENT - Failed to create a shared memory segment\n"); exit(1); } shmid = rc; printf("PARENT - Attach the shared memory\n"); sharedMem = shmat(shmid, NULL, 0); if (sharedMem == NULL) { shmctl(shmid, IPC_RMID, NULL); printf("PARENT - Failed to attach shared memory\n"); exit(1); } /***************************************************************/ /* Initialize the read/write lock and other shared memory data */ /***************************************************************/ { pthread_rwlockattr_t rwlattr; printf("PARENT - Init shared memory and read/write lock\n"); memset(sharedMem, 0, sizeof(shared_data_t)); /* Process Shared Read/Write lock */ rc = pthread_rwlockattr_init(&rwlattr); checkResults("pthread_rwlockattr_init()\n", rc); rc = pthread_rwlockattr_setpshared(&rwlattr, PTHREAD_PROCESS_SHARED); checkResults("pthread_rwlockattr_setpshared()\n", rc); rc = pthread_rwlock_init(&sharedMem->rwlock, &rwlattr); checkResults("pthread_rwlock_init()\n", rc); } /**************************************************************/ /* Set and environment variable so that the child can inherit */ /* it and know the shared memory ID */ /**************************************************************/
{ char shmIdEnvVar[128]; sprintf(shmIdEnvVar, "TPRWLSH0_SHMID=%d\n", shmid); rc = putenv(shmIdEnvVar); if (rc) { printf("PARENT - Failed to store env var %s, errno=%d\n", shmIdEnvVar, errno); exit(1); } printf("PARENT - Stored shared memory id of %d\n", shmid); } /**************************************************/ /* Spawn the child job */ /**************************************************/ { inheritance_t in; char *av[3] = {NULL, NULL, NULL}; /* Allow thread creation in the spawned child memset(&in, 0, sizeof(in)); in.flags = SPAWN_SETTHREAD_NP; /* Set up the arguments to pass to spawn based on the /* arguments passed in av[0] = MYPATH; av[1] = "ASCHILD"; av[2] = NULL; */
*/ */
/* Spawn the child that was specified, inheriting all */ /* of the environment variables. */ childPid = spawn(MYPATH, 0, NULL, &in, av, environ); if (childPid == -1) { /* spawn failure */ printf("PARENT - spawn() failed, errno=%d\n", errno); exit(1); } printf("PARENT - spawn() success, [PID=%d]\n", childPid); } return; } /***************************************************************/ /* This function attaches the shared memory for the child job, */ /* It uses the environment variable indicating where the shared*/ /* memory is. */ /* */ /* If any of this setup/initialization fails, it will exit(1) */ /* and terminate the test. */ /* */ /* It initializes the following global variables: */ /* sharedMem */ /* shmid */ /***************************************************************/ void childSetup(void) { int rc; printf("CHILD - Child setup\n");
/**************************************************************/ /* Set and environment variable so that the child can inherit */ /* it and know the shared memory ID */ /**************************************************************/ { char *shmIdEnvVar; shmIdEnvVar = getenv("TPRWLSH0_SHMID"); if (shmIdEnvVar == NULL) { printf("CHILD - Failed to get env var \"TPRWLSH0_SHMID\", errno=%d\n", errno); exit(1); } shmid = atoi(shmIdEnvVar); printf("CHILD - Got shared memory id of %d\n", shmid); } /***************************************************************/ /* Create shared memory for shared_data_t above */ /* attach the shared memory */ /* set the static/global sharedMem pointer to it */ /***************************************************************/ printf("CHILD - Attach the shared memory\n"); sharedMem = shmat(shmid, NULL, 0); if (sharedMem == NULL) { shmctl(shmid, IPC_RMID, NULL); printf("CHILD - Failed to attach shared memory\n"); exit(1); } return; } /***************************************************************/ /* wait for child to complete and get return code. */ /* Destroy read/write lock in shared memory */ /* detach and remove shared memory */ /* set the child's return code in global storage */ /* */ /* If this function fails, it will call exit(1) */ /* */ /* This function sets the following global variables: */ /* sharedMem */ /* childStatus */ /* shmid */ /***************************************************************/ void parentCleanup(void) { int status=0; int rc; int waitedPid=0; /* Even though there is no thread left in the child using the /* contents of the shared memory, before we destroy the /* read/write lock in that shared memory, we will wait for the /* child job to complete, we know for 100% certainty that no /* threads in the child are using it then, because the child /* is terminated. printf("PARENT - Parent cleanup\n"); /* Wait for the child to complete */ waitedPid = waitpid(childPid,&status,0); if (rc == -1) { printf("PARENT - waitpid failed, errno=%d\n", errno); */ */ */ */ */ */
exit(1); } childStatus = status; /* Cleanup resources */ rc = pthread_rwlock_destroy(&sharedMem->rwlock); checkResults("pthread_rwlock_destroy()\n", rc); /* Detach/Remove shared memory */ rc = shmdt(sharedMem); if (rc) { printf("PARENT - Failed to detach shared memory, errno=%d\n", errno); exit(1); } rc = shmctl(shmid, IPC_RMID, NULL); if (rc) { printf("PARENT - Failed to remove shared memory id=%d, errno=%d\n", shmid, errno); exit(1); } shmid = 0; return; } /***************************************************************/ /* Detach the shared memory */ /* At this point, there is no serialization, so the contents */ /* of the shared memory should not be used. */ /* */ /* If this function fails, it will call exit(1) */ /* */ /* This function sets the following global variables: */ /* sharedMem */ /***************************************************************/ void childCleanup(void) { int rc; printf("CHILD - Child cleanup\n"); rc = shmdt(sharedMem); sharedMem = NULL; if (rc) { printf("CHILD - Failed to detach shared memory, errno=%d\n", errno); exit(1); } return; }
Output:
This example was run under the OS/400 QShell Interpreter. In the QShell Interpreter, a program gets descriptors 0, 1, 2 as the standard files, the parent and child I/O is directed to the console. When run in the QShell Interpreter, the output shows the intermixed output from both parent and child processes, and gives a feeling for the time sequence of operations occurring in each job. The QShell interpreter allows you to run multithreaded programs as if they were interactive. See the QShell documentation for a description of the QIBM_MULTI_THREADED shell variable which allows you to start multithreaded programs. The QShell Interpreter is option 30 of Base OS/400.
PARENT - Enter Testcase - QP0WTEST/TPRWLSH0 PARENT - Create the shared memory segment PARENT - Attach the shared memory PARENT - Init shared memory and read/write lock PARENT - Stored shared memory id of 7 PARENT - spawn() success, [PID=584] PARENT - Create 2 threads PARENT WRITER - current protectedResource = 1 CHILD - Enter Testcase - QP0WTEST/TPRWLSH0 CHILD - Child setup CHILD - Got shared memory id of 7 CHILD - Attach the shared memory CHILD - Create 2 threads CHILD - Joining to all threads PARENT WRITER - unlock PARENT WRITER - current protectedResource = 2 PARENT WRITER - unlock CHILD READER - current protectedResource = 2 CHILD READER - current protectedResource = 2 PARENT - Parent cleanup CHILD READER - unlock CHILD READER - current protectedResource = 2 CHILD READER - unlock CHILD READER - current protectedResource = 2 CHILD READER - unlock CHILD READER - current protectedResource = 2 CHILD READER - unlock CHILD READER - current protectedResource = 2 CHILD READER - unlock CHILD READER - current protectedResource = 2 CHILD READER - unlock CHILD READER - current protectedResource = 2 CHILD READER - unlock CHILD READER - current protectedResource = 2 CHILD READER - unlock CHILD READER - current protectedResource = 2 CHILD READER - unlock CHILD READER - unlock CHILD - Child cleanup CHILD - Main completed PARENT - Main completed
Parameters
attr (Output) Address of the variable to contain the read/write lock attributes object
Return Value
0 pthread_rwlockattr_init() was successful. value pthread_rwlockattr_init() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlockattr_init() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlockattr_destroy()--Destroy Read/Write Lock Attribute pthread_rwlock_init()--Initialize Read/Write Lock
Example
See the pthread_rwlockattr_destroy() example.
Parameters
attr (Input) Address of the variable containing the read/write lock attributes object pshared (Input) One of PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE
Return Value
0 pthread_rwlockattr_setpshared() was successful. value pthread_rwlockattr_setpshared() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlockattr_setpshared() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlockattr_init()--Initialize Read/Write Lock Attribute pthread_rwlockattr_getpshared()--Get Pshared Read/Write Lock Attribute pthread_rwlock_init()--Initialize Read/Write Lock
Example
See the pthread_rwlockattr_getpshared() example.
Parameters
rwlock (Input) Address of the read/write lock to be destroyed
Return Value
0 pthread_rwlock_destroy() was successful. value pthread_rwlock_destroy() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_destroy() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlock_init()--Initialize Read/Write Lock
Example
See the pthread_rwlock_init() example.
Parameters
rwlock (Output) The address of the variable to contain a read/write lock attr (Input) The address of the variable containing the read/write lock attributes object
Return Value
0 pthread_rwlock_init() was successful. value pthread_rwlock_init() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_init() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlockattr_init()--Initialize Read/Write Lock Attribute pthread_rwlock_destroy()--Destroy Read/Write Lock
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_rwlock_t rwlock;
void *rdlockThread(void *arg) { int rc; printf("Entered thread, getting read lock\n"); rc = pthread_rwlock_rdlock(&rwlock); checkResults("pthread_rwlock_rdlock()\n", rc); printf("got the rwlock read lock\n"); sleep(5); printf("unlock the read lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Secondary thread unlocked\n"); return NULL; } void *wrlockThread(void *arg) { int rc; printf("Entered thread, getting write lock\n"); rc = pthread_rwlock_wrlock(&rwlock); checkResults("pthread_rwlock_wrlock()\n", rc); printf("Got the rwlock write lock, now unlock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Secondary thread unlocked\n"); return NULL; } int main(int argc, char **argv) { int rc=0; pthread_t thread, thread1; printf("Enter Testcase - %s\n", argv[0]); printf("Main, initialize the read write lock\n"); rc = pthread_rwlock_init(&rwlock, NULL);
checkResults("pthread_rwlock_init()\n", rc); printf("Main, grab a read lock\n"); rc = pthread_rwlock_rdlock(&rwlock); checkResults("pthread_rwlock_rdlock()\n",rc); printf("Main, grab the same read lock again\n"); rc = pthread_rwlock_rdlock(&rwlock); checkResults("pthread_rwlock_rdlock() second\n", rc); printf("Main, create the read lock thread\n"); rc = pthread_create(&thread, NULL, rdlockThread, NULL); checkResults("pthread_create\n", rc); printf("Main - unlock the first read lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Main, create the write lock thread\n"); rc = pthread_create(&thread1, NULL, wrlockThread, NULL); checkResults("pthread_create\n", rc); sleep(5); printf("Main - unlock the second read lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Main, wait for the threads\n"); rc = pthread_join(thread, NULL); checkResults("pthread_join\n", rc); rc = pthread_join(thread1, NULL); checkResults("pthread_join\n", rc); rc = pthread_rwlock_destroy(&rwlock); checkResults("pthread_rwlock_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPRWLINI0 Main, initialize the read write lock Main, grab a read lock Main, grab the same read lock again Main, create the read lock thread Main - unlock the first read lock Main, create the write lock thread Entered thread, getting read lock got the rwlock read lock Entered thread, getting write lock Main - unlock the second read lock Main, wait for the threads unlock the read lock Secondary thread unlocked Got the rwlock write lock, now unlock Secondary thread unlocked Main completed
Parameters
rwlock (Input) The address of the read/write lock
Return Value
0 pthread_rwlock_rdlock() was successful. value pthread_rwlock_rdlock() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_rdlock() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EDESTROYED] The lock was destroyed while waiting.
Related Information
q q q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlock_init()--Initialize Read/Write Lock pthread_rwlock_timedrdlock_np()--Get Shared Read Lock with Time-out pthread_rwlock_timedwrlock_np()--Get Exclusive Write Lock with Time-out pthread_rwlock_tryrdlock()--Get Shared Read Lock with No Wait pthread_rwlock_trywrlock()--Get Exclusive Write Lock with No Wait pthread_rwlock_unlock()--Unlock Exclusive Write or Shared Read Lock pthread_rwlock_wrlock()--Get Exclusive Write Lock
Example
See the pthread_rwlock_init() example.
pthread_rwlock_unlock() will unlock the shared read locks. You can use this behavior to allow your application to upgrade or downgrade one lock type to another. See Read/write locks can be upgraded/downgraded.
Parameters
rwlock (Input) The address of the read/write lock deltatime (Input) The number of seconds and nanoseconds to wait for the lock before returning an error
Return Value
0 pthread_rwlock_timedrdlock_np() was successful. value pthread_rwlock_timedrdlock_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_timedrdlock_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EBUSY] The lock could not be acquired in the time specified. [EDESTROYED] The lock was destroyed while waiting.
Related Information
q q q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlock_init()--Initialize Read/Write Lock pthread_rwlock_rdlock()--Get Shared Read Lock pthread_rwlock_timedwrlock_np()--Get Exclusive Write Lock with Time-Out pthread_rwlock_tryrdlock()--Get Shared Read Lock with No Wait pthread_rwlock_trywrlock()--Get Exclusive Write Lock with No Wait pthread_rwlock_unlock()--Unlock Exclusive Write or Shared Read Lock pthread_rwlock_wrlock()--Get Exclusive Write Lock
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
void *rdlockThread(void *arg) { int rc; int count=0; struct timespec ts; /* 1.5 seconds */ ts.tv_sec = 1; ts.tv_nsec = 500000000; printf("Entered thread, getting read lock with timeout\n"); Retry: rc = pthread_rwlock_timedrdlock_np(&rwlock, &ts); if (rc == EBUSY) { if (count >= 10) { printf("Retried too many times, failure!\n"); exit(EXIT_FAILURE); } ++count; printf("RETRY...\n"); goto Retry; } checkResults("pthread_rwlock_rdlock() 1\n", rc); sleep(2); printf("unlock the read lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Secondary thread complete\n"); return NULL; } int main(int argc, char **argv) { int rc=0; pthread_t thread; printf("Enter Testcase - %s\n", argv[0]); printf("Main, get the write lock\n"); rc = pthread_rwlock_wrlock(&rwlock); checkResults("pthread_rwlock_wrlock()\n", rc); printf("Main, create the timed rd lock thread\n"); rc = pthread_create(&thread, NULL, rdlockThread, NULL); checkResults("pthread_create\n", rc); printf("Main, wait a bit holding the write lock\n"); sleep(5);
printf("Main, Now unlock the write lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Main, wait for the thread to end\n"); rc = pthread_join(thread, NULL); checkResults("pthread_join\n", rc); rc = pthread_rwlock_destroy(&rwlock); checkResults("pthread_rwlock_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPRWLRD0 Main, get the write lock Main, create the timed rd lock thread Main, wait a bit Entered thread, getting read lock with timeout RETRY... RETRY... RETRY... Main, Now unlock the write lock Main, wait for the thread to end unlock the read lock Secondary thread complete Main completed
the exclusive write locks are unlocked first. If more than one outstanding exclusive write lock was held by the thread, a matching number of successful calls to pthread_rwlock_unlock() must be done before all write locks are unlocked. At that time, subsequent calls to pthread_rwlock_unlock() unlock the shared read locks. You can use this behavior to allow your application to upgrade or downgrade one lock type to another. See Read/write locks can be upgraded and downgraded.
Parameters
rwlock (Input) The address of the read/write lock deltatime (Input) The number of seconds and nanoseconds to wait for the lock before returning an error
Return Value
0 pthread_rwlock_timedwrlock_np() was successful. value pthread_rwlock_timedwrlock_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_timedwrlock_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EBUSY] The lock could not be acquired in the time specified. [EDESTROYED] The lock was destroyed while waiting.
Related Information
q q q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlock_init()--Initialize Read/Write Lock pthread_rwlock_rdlock()--Get Shared Read Lock pthread_rwlock_timedrdlock_np()--Get Shared Read Lock with Time-Out pthread_rwlock_tryrdlock()--Get Shared Read Lock with No Wait pthread_rwlock_trywrlock()--Get Exclusive Write Lock with No Wait pthread_rwlock_unlock()--Unlock Exclusive Write or Shared Read Lock pthread_rwlock_wrlock()--Get Exclusive Write Lock
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
void *wrlockThread(void *arg) { int rc; int count=0; struct timespec ts; /* 1.5 seconds */ ts.tv_sec = 1; ts.tv_nsec = 500000000; printf("%.8x %.8x: Entered thread, getting write lock with timeout\n", pthread_getthreadid_np()); Retry: rc = pthread_rwlock_timedwrlock_np(&rwlock, &ts); if (rc == EBUSY) { if (count >= 10) { printf("%.8x %.8x: Retried too many times, failure!\n", pthread_getthreadid_np()); exit(EXIT_FAILURE); } ++count; printf("%.8x %.8x: RETRY...\n", pthread_getthreadid_np()); goto Retry; } checkResults("pthread_rwlock_wrlock() 1\n", rc); printf("%.8x %.8x: Got the write lock\n", pthread_getthreadid_np()); sleep(2); printf("%.8x %.8x: Unlock the write lock\n", pthread_getthreadid_np()); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("%.8x %.8x: Secondary thread complete\n", pthread_getthreadid_np()); return NULL; } int main(int argc, char **argv) { int rc=0; pthread_t thread, thread2; printf("Enter Testcase - %s\n", argv[0]); printf("Main, get the write lock\n"); rc = pthread_rwlock_wrlock(&rwlock); checkResults("pthread_rwlock_wrlock()\n", rc); printf("Main, create the timed write lock threads\n");
rc = pthread_create(&thread, NULL, wrlockThread, NULL); checkResults("pthread_create\n", rc); rc = pthread_create(&thread2, NULL, wrlockThread, NULL); checkResults("pthread_create\n", rc); printf("Main, wait a bit holding this write lock\n"); sleep(3); printf("Main, Now unlock the write lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Main, wait for the threads to end\n"); rc = pthread_join(thread, NULL); checkResults("pthread_join\n", rc); rc = pthread_join(thread2, NULL); checkResults("pthread_join\n", rc); rc = pthread_rwlock_destroy(&rwlock); checkResults("pthread_rwlock_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output:
Enter Testcase - QP0WTEST/TPRWLWR0 Main, get the write lock Main, create the timed write lock threads Main, wait a bit holding this write lock 00000000 00000017: Entered thread, getting write lock with timeout 00000000 00000018: Entered thread, getting write lock with timeout 00000000 00000017: RETRY... 00000000 00000018: RETRY... Main, Now unlock the write lock Main, wait for the threads to end 00000000 00000017: Got the write lock 00000000 00000018: RETRY... 00000000 00000018: RETRY... 00000000 00000017: Unlock the write lock 00000000 00000017: Secondary thread complete 00000000 00000018: Got the write lock 00000000 00000018: Unlock the write lock 00000000 00000018: Secondary thread complete Main completed
Parameters
rwlock (Input) The address of the read/write lock
Return Value
0 pthread_rwlock_tryrdlock() was successful. value pthread_rwlock_tryrdlock() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_tryrdlock() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EBUSY] The lock could not be immediately acquired.
Related Information
q q q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlock_init()--Initialize Read/Write Lock pthread_rwlock_rdlock()--Get Shared Read Lock pthread_rwlock_timedrdlock_np()--Get Shared Read Lock with Time-Out pthread_rwlock_timedwrlock_np()--Get Exclusive Write Lock with Time-Out pthread_rwlock_trywrlock()--Get Exclusive Write Lock with No Wait pthread_rwlock_unlock()--Unlock Exclusive Write or Shared Read Lock pthread_rwlock_wrlock()--Get Exclusive Write Lock
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
void *rdlockThread(void *arg) { int rc; int count=0; printf("Entered thread, getting read lock with mp wait\n"); Retry: rc = pthread_rwlock_tryrdlock(&rwlock); if (rc == EBUSY) { if (count >= 10) {
printf("Retried too many times, failure!\n"); exit(EXIT_FAILURE); } ++count; printf("Could not get lock, do other work, then RETRY...\n"); sleep(1); goto Retry; } checkResults("pthread_rwlock_tryrdlock() 1\n", rc); sleep(2); printf("unlock the read lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Secondary thread complete\n"); return NULL; } int main(int argc, char **argv) { int rc=0; pthread_t thread; printf("Enter Testcase - %s\n", argv[0]); printf("Main, get the write lock\n"); rc = pthread_rwlock_wrlock(&rwlock); checkResults("pthread_rwlock_wrlock()\n", rc); printf("Main, create the try read lock thread\n"); rc = pthread_create(&thread, NULL, rdlockThread, NULL); checkResults("pthread_create\n", rc); printf("Main, wait a bit holding the write lock\n"); sleep(5); printf("Main, Now unlock the write lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Main, wait for the thread to end\n"); rc = pthread_join(thread, NULL); checkResults("pthread_join\n", rc); rc = pthread_rwlock_destroy(&rwlock); checkResults("pthread_rwlock_destroy()\n", rc); printf("Main completed\n"); return 0; }
Output
Enter Main, Main, Main, Testcase - QP0WTEST/TPRWLRD1 get the write lock create the try read lock thread wait a bit holding the write lock
Entered thread, getting read lock with mp wait Could not get lock, do other work, then RETRY... Could not get lock, do other work, then RETRY... Could not get lock, do other work, then RETRY... Could not get lock, do other work, then RETRY... Could not get lock, do other work, then RETRY... Main, Now unlock the write lock Main, wait for the thread to end unlock the read lock Secondary thread complete Main completed
Parameters
rwlock (Input) The address of the read/write lock
Return Value
0 pthread_rwlock_trywrlock() was successful. value pthread_rwlock_trywrlock() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_trywrlock() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EBUSY] The lock could not be acquired in the timed specified.
Related Information
q q q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlock_init()--Initialize Read/Write Lock pthread_rwlock_rdlock()--Get Shared Read Lock pthread_rwlock_timedrdlock_np()--Get Shared Read Lock with Time-Out pthread_rwlock_timedwrlock_np()--Get Exclusive Write Lock with Time-Out pthread_rwlock_tryrdlock()--Get Shared Read Lock with No Wait pthread_rwlock_unlock()--Unlock Exclusive Write or Shared Read Lock pthread_rwlock_wrlock()--Get Exclusive Write Lock
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
void *wrlockThread(void *arg) { int rc; int count=0; printf("%.8x %.8x: Entered thread, getting write lock with timeout\n", pthread_getthreadid_np()); Retry: rc = pthread_rwlock_trywrlock(&rwlock); if (rc == EBUSY) {
if (count >= 10) { printf("%.8x %.8x: Retried too many times, failure!\n", pthread_getthreadid_np()); exit(EXIT_FAILURE); } ++count; printf("%.8x %.8x: Go off an do other work, then RETRY...\n", pthread_getthreadid_np()); sleep(1); goto Retry; } checkResults("pthread_rwlock_trywrlock() 1\n", rc); printf("%.8x %.8x: Got the write lock\n", pthread_getthreadid_np()); sleep(2); printf("%.8x %.8x: Unlock the write lock\n", pthread_getthreadid_np()); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("%.8x %.8x: Secondary thread complete\n", pthread_getthreadid_np()); return NULL; } int main(int argc, char **argv) { int rc=0; pthread_t thread, thread2; printf("Enter Testcase - %s\n", argv[0]); printf("Main, get the write lock\n"); rc = pthread_rwlock_wrlock(&rwlock); checkResults("pthread_rwlock_wrlock()\n", rc); printf("Main, create the timed write lock threads\n"); rc = pthread_create(&thread, NULL, wrlockThread, NULL); checkResults("pthread_create\n", rc); rc = pthread_create(&thread2, NULL, wrlockThread, NULL); checkResults("pthread_create\n", rc); printf("Main, wait a bit holding this write lock\n"); sleep(1); printf("Main, Now unlock the write lock\n"); rc = pthread_rwlock_unlock(&rwlock); checkResults("pthread_rwlock_unlock()\n", rc); printf("Main, wait for the threads to end\n"); rc = pthread_join(thread, NULL); checkResults("pthread_join\n", rc); rc = pthread_join(thread2, NULL); checkResults("pthread_join\n", rc); rc = pthread_rwlock_destroy(&rwlock); checkResults("pthread_rwlock_destroy()\n", rc); printf("Main completed\n");
return 0; }
Output:
Enter Testcase - QP0WTEST/TPRWLWR1 Main, get the write lock Main, create the timed write lock threads 00000000 0000000d: Entered thread, getting write 00000000 0000000d: Go off an do other work, then Main, wait a bit holding this write lock 00000000 0000000e: Entered thread, getting write 00000000 0000000e: Go off an do other work, then 00000000 0000000d: Go off an do other work, then Main, Now unlock the write lock Main, wait for the threads to end 00000000 0000000e: Got the write lock 00000000 0000000d: Go off an do other work, then 00000000 0000000e: Unlock the write lock 00000000 0000000e: Secondary thread complete 00000000 0000000d: Got the write lock 00000000 0000000d: Unlock the write lock 00000000 0000000d: Secondary thread complete Main completed
RETRY...
Parameters
rwlock (Input) The address of the read/write lock
Return Value
0 pthread_rwlock_unlock() was successful. value pthread_rwlock_unlock() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_unlock() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EPERM] A shared read or exclusive write lock was not held by the calling thread and could not be unlocked.
Related Information
q q q q q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_rwlock_init()--Initialize Read/Write Lock pthread_rwlock_rdlock()--Get Shared Read Lock pthread_rwlock_timedrdlock_np()--Get Shared Read Lock with Time-Out pthread_rwlock_timedwrlock_np()--Get Exclusive Write Lock with Time-Out pthread_rwlock_tryrdlock()--Get Shared Read Lock with No Wait pthread_rwlock_trywrlock()--Get Exclusive Write Lock with No Wait pthread_rwlock_wrlock()--Get Exclusive Write Lock
Example
See any of the following examples:
q q q q
Parameters
rwlock (Input) The address of the read/write lock
Return Value
0 pthread_rwlock_wrlock() was successful. value pthread_rwlock_wrlock() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_rwlock_wrlock() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [EDESTROYED] The lock was destroyed while waiting.
Related Information
q q q q q q q q
The <pthread.h> header file. See Header files for Pthread functions pthread_rwlock_init()--Initialize a Read/Write Lock pthread_rwlock_rdlock()--Get a Shared Read Lock pthread_rwlock_timedrdlock_np()--Get a Shared Read Lock with Time-Out pthread_rwlock_timedwrlock_np()--Get an Exclusive Write Lock with Time-Out pthread_rwlock_tryrdlock()--Get a Shared Read Lock with No Wait pthread_rwlock_trywrlock()--Get an Exclusive Write Lock with No Wait pthread_rwlock_unlock()--Unlock an Exclusive Write or Shared Read Lock
Example
See the pthread_rwlock_init() example.
Signals APIs
Signals APIs
Signal APIs can be used to manipulate signals in a threaded process. Signals can be sent to individual threads, the signal mask of a thread can be changed. When a signal is sent to a thread, the actions associated with the signal (such as stopping, continuing or terminating) never affect only the thread, all signal actions are defined to affect the process. When a signal handler is invoked, it is invoked in the thread that the signal was delivered to. Using signals correctly in a multithreaded process can be difficult. The recommended way to handle signals in a multithreaded process is to mask off all signals in all threads, then use the signals sigwait() API in a single thread to wait for any signal to be delivered to the process. For information about the examples included with the APIs, see the information on the API examples. To view the API list by description, see Signals APIs. Signals APIs by name
q q q
pthread_kill()--Send Signal to Thread pthread_sigmask()--Set or Get Signal Mask pthread_signal_to_cancel_np()--Convert Signals to Cancel Requests
Parameters
thread (Input) Pthread handle of the target thread sig (Input) The signal number to be delivered or zero to validate the pthread_t
Return Value
0 pthread_kill() was successful. value pthread_kill() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_kill() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [ESRCH] No thread could be found that matched the thread ID specified. [EINVAL] The value specified for the argument is not correct. [ENOTSIGINIT]
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_sigmask()--Set or Get Signal Mask pthread_signal_to_cancel_np()--Convert Signals to Cancel Requests
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <sys/signal.h> #include "check.h" #define NUMTHREADS 3 void sighand(int signo); void *threadfunc(void *parm) { pthread_t self = pthread_self(); pthread_id_np_t tid; int rc; pthread_getunique_np(&self, &tid); printf("Thread 0x%.8x %.8x entered\n", tid); errno = 0; rc = sleep(30); if (rc != 0 && errno == EINTR) { printf("Thread 0x%.8x %.8x got a signal delivered to it\n", tid); return NULL; } printf("Thread 0x%.8x %.8x did not get expected results! rc=%d, errno=%d\n", tid, rc, errno); return NULL; } int main(int argc, char **argv) { int rc; int i; struct sigaction actions; pthread_t threads[NUMTHREADS]; printf("Enter Testcase - %s\n", argv[0]); printf("Set up the alarm handler for the process\n"); memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = sighand; rc = sigaction(SIGALRM,&actions,NULL); checkResults("sigaction\n", rc);
for(i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&threads[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); } sleep(3); for(i=0; i<NUMTHREADS; ++i) { rc = pthread_kill(threads[i], SIGALRM); checkResults("pthread_kill()\n", rc); } for(i=0; i<NUMTHREADS; ++i) { rc = pthread_join(threads[i], NULL); checkResults("pthread_join()\n", rc); } printf("Main completed\n"); return 0; } void sighand(int signo) { pthread_t self = pthread_self(); pthread_id_np_t tid; pthread_getunique_np(&self, &tid); printf("Thread 0x%.8x %.8x in signal handler\n", tid); return; }
Output:
Enter Testcase - QP0WTEST/TPKILL0 Set up the alarm handler for the process Thread 0x00000000 0000000c entered Thread 0x00000000 0000000d entered Thread 0x00000000 0000000e entered Thread 0x00000000 0000000c in signal handler Thread 0x00000000 0000000c got a signal delivered to it Thread 0x00000000 0000000d in signal handler Thread 0x00000000 0000000d got a signal delivered to it Thread 0x00000000 0000000e in signal handler Thread 0x00000000 0000000e got a signal delivered to it Main completed
Parameters
how (Input) The way in which the signal set is changed set (Input) A pointer to a set of signals to be used to change the currently blocked set. This value can be NULL oset (Output) A pointer to the space where the previous signal mask is stored. This value can be NULL
Return Value
0 pthread_sigmask() was successful. value pthread_sigmask() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_sigmask() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct. [ENOTSIGINIT] The process is not enabled for signals.
Related Information
q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_kill()--Send Signal to Thread pthread_signal_to_cancel_np()--Convert Signals to Cancel Requests
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <sys/signal.h> #include "check.h" #define NUMTHREADS 3 void sighand(int signo); void *threadfunc(void *parm) { pthread_t self = pthread_self(); pthread_id_np_t tid; int rc; pthread_getunique_np(&self, &tid); printf("Thread 0x%.8x %.8x entered\n", tid); errno = 0; rc = sleep(30); if (rc != 0 && errno == EINTR) { printf("Thread 0x%.8x %.8x got a signal delivered to it\n", tid); return NULL; } printf("Thread 0x%.8x %.8x did not get expected results! rc=%d,
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/users_96.htm (2 of 4) [2/9/2001 2:05:29 PM]
errno=%d\n", tid, rc, errno); return NULL; } void *threadmasked(void { pthread_t pthread_id_np_t sigset_t int *parm) self = pthread_self(); tid; mask; rc;
pthread_getunique_np(&self, &tid); printf("Masked thread 0x%.8x %.8x entered\n", tid); sigfillset(&mask); /* Mask all allowed signals */ rc = pthread_sigmask(SIG_BLOCK, &mask, NULL); checkResults("pthread_sigmask()\n", rc); errno = 0; rc = sleep(15); if (rc != 0) { printf("Masked thread 0x%.8x %.8x did not get expected results! " "rc=%d, errno=%d\n", tid, rc, errno); return NULL; } printf("Masked thread 0x%.8x %.8x completed masked work\n", tid); return NULL; } int main(int argc, char **argv) { int rc; int i; struct sigaction actions; pthread_t threads[NUMTHREADS]; pthread_t maskedthreads[NUMTHREADS]; printf("Enter Testcase - %s\n", argv[0]); printf("Set up the alarm handler for the process\n"); memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = sighand; rc = sigaction(SIGALRM,&actions,NULL); checkResults("sigaction\n", rc); printf("Create masked and unmasked threads\n"); for(i=0; i<NUMTHREADS; ++i) { rc = pthread_create(&threads[i], NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); rc = pthread_create(&maskedthreads[i], NULL, threadmasked, NULL); checkResults("pthread_create()\n", rc); } sleep(3);
printf("Send a signal to masked and unmasked threads\n"); for(i=0; i<NUMTHREADS; ++i) { rc = pthread_kill(threads[i], SIGALRM); checkResults("pthread_kill()\n", rc); rc = pthread_kill(maskedthreads[i], SIGALRM); checkResults("pthread_kill()\n", rc); } printf("Wait for masked and unmasked threads to complete\n"); for(i=0; i<NUMTHREADS; ++i) { rc = pthread_join(threads[i], NULL); checkResults("pthread_join()\n", rc); rc = pthread_join(maskedthreads[i], NULL); checkResults("pthread_join()\n", rc); } printf("Main completed\n"); return 0; } void sighand(int signo) { pthread_t self = pthread_self(); pthread_id_np_t tid; pthread_getunique_np(&self, &tid); printf("Thread 0x%.8x %.8x in signal handler\n", tid); return; }
Output:
Thread 0x00000000 0000000d entered Masked thread 0x00000000 0000000a entered Thread 0x00000000 00000009 entered Thread 0x00000000 0000000b entered Masked thread 0x00000000 0000000e entered Masked thread 0x00000000 0000000c entered Send a signal to masked and unmasked threads Wait for masked and unmasked threads to complete Thread 0x00000000 00000009 in signal handler Thread 0x00000000 00000009 got a signal delivered to it Thread 0x00000000 0000000b in signal handler Thread 0x00000000 0000000b got a signal delivered to it Thread 0x00000000 0000000d in signal handler Thread 0x00000000 0000000d got a signal delivered to it Masked thread 0x00000000 0000000a completed masked work Masked thread 0x00000000 0000000e completed masked work Masked thread 0x00000000 0000000c completed masked work Main completed
Parameters
set (Input) The set of signals that will be converted to pthread_cancel() requests thread (Input) The thread that will be canceled when a signal in set arrives
Return Value
0 pthread_signal_to_cancel_np() was successful. value pthread_signal_to_cancel_np() was not successful. value is set to indicate the error condition.
Error Conditions
If pthread_signal_to_cancel_np() was not successful, the error condition returned usually indicates one of the following errors. Under some conditions, the value returned could indicate an error other than those listed here. [EINVAL] The value specified for the argument is not correct.
Related Information
q q q q
The <pthread.h> header file. See Header files for Pthread functions. pthread_cancel()--Cancel Thread pthread_kill()--Send Signal to Thread pthread_sigmask()--Set or Get Signal Mask
Example
#define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include <sys/signal.h> #include "check.h" void sighand(int signo); void cancellationCleanup(void *parm) { printf("Thread was canceled\n"); } void *threadfunc(void *parm) { pthread_t self = pthread_self(); pthread_id_np_t tid; int rc; int i=5; pthread_getunique_np(&self, &tid); printf("Thread 0x%.8x %.8x entered\n", tid); while (i--) { printf("Thread 0x%.8x %.8x looping\n", tid, rc, errno); sleep(2); pthread_testcancel(); } printf("Thread 0x%.8x %.8x did not expect to get here\n", tid); return NULL; } int main(int argc, char **argv) { int rc; int i; pthread_t thread; struct sigaction actions; sigset_t mask; void *status; pthread_t self;
pthread_id_np_t
tid;
printf("Enter Testcase - %s\n", argv[0]); printf("Set up the alarm handler for the process\n"); memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = sighand; rc = sigaction(SIGALRM,&actions,NULL); checkResults("sigaction\n", rc); printf("Block all signals in the parent so they can be inherited\n"); sigfillset(&mask); /* Mask all allowed signals */ rc = pthread_sigmask(SIG_BLOCK, &mask, NULL); checkResults("pthread_sigmask()\n", rc); printf("Create thread that inherits blocking mask\n"); /* Thread will inherit blocking mask */ rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); /* Convert signals to cancels */ rc = pthread_signal_to_cancel_np(&mask, &thread); checkResults("pthread_signal_to_cancel()\n", rc); sleep(3); self = pthread_self(); pthread_getunique_np(&self, &tid); printf("Thread 0x%.8x %.8x sending a signal to the process\n", tid); kill(getpid(), SIGALRM); checkResults("kill()\n", rc); printf("Wait for masked and unmasked threads to complete\n"); rc = pthread_join(thread, &status); checkResults("pthread_join()\n", rc); if (status != PTHREAD_CANCELED) { printf("Got an incorrect thread status\n"); return 1; } printf("The target thread was canceled\n"); printf("Main completed\n"); return 0; } void sighand(int signo) { pthread_t self = pthread_self(); pthread_id_np_t tid; pthread_getunique_np(&self, &tid); printf("Thread 0x%.8x %.8x in signal handler\n", tid); return; }
Output:
Enter Testcase - QP0WTEST/TPSIG2C0 Set up the alarm handler for the process Block all signals in the parent so they can be inherited Create thread that inherits blocking mask Thread 0x00000000 00000007 entered Thread 0x00000000 00000007 looping Thread 0x00000000 00000007 looping Thread 0x00000000 00000006 sending a signal to the process Wait for masked and unmasked threads to complete The target thread was canceled Main completed
Type pthread_attr_t pthread_cleanup_entry_np_t pthread_condattr_t pthread_cond_t pthread_joinoption_np_t pthread_key_t pthread_mutexattr_t pthread_mutex_t pthread_once_t pthread_option_np_t pthread_rwlockattr_t pthread_rwlock_t pthread_t pthread_id_np_t struct sched_param
Description Thread creation attribute Cancellation cleanup handler entry Condition variable creation attribute Condition Variable synchronization primitive Options structure for extensions to pthread_join() Thread local storage key Mutex creation attribute Mutex (Mutual exclusion) synchronization primitive Once time initialization control variable Pthread run-time options structure Read/Write lock attribute Read/Write synchronization primitive Pthread handle Thread ID. For use as an integral type. Scheduling parameters (priority and policy)
After creating the primitive objects of type pthread_cond_t and pthread_mutex_t using the appropriate initialization functions, those objects must not be copied or moved to a new location. If the condition variable or mutex is copied or moved to a new location, the new primitive object is not valid or usable. Attempts to use the new object result in the EINVAL error.
OS/400 Pthreads versus the POSIX standard, the Single UNIX Specification, and other threads implementations
OS/400 Pthreads versus the POSIX standard, the Single UNIX Specification, and other threads implementations
Although the Pthread interfaces described in this document are based on a subset of the APIs defined in the POSIX standard and the Single UNIX Specification, the implementation of these APIs is not compliant with these standards. This means that applications written in other versions of threads are not necessarily portable to OS/400. Below is a list of the differences between the Pthread APIs and other threads implementations.
q q q q q q q q q q q q q q q q q q q q q q q q
All thread definitions in pthread.h Unsupported preprocessor and feature test macros Unsupported APIs Unsupported constants Unsupported cancellation points Unsupported sysconf() configuration variables Thread priority and scheduling Thread ID vs. Pthread Handle (pthread_t) Thread ID value and size Mutexes return EDEADLK when re-locked by owner Return values from thread start routines are not integers Threads do not necessarily start before pthread_create() returns Initial thread is special, cannot pthread_exit() Pthread APIs cause asynchronous signals initialization Not all jobs can create threads; pthread_create() fails with EBUSY Read/write locks are recursive Shared read/write locks are released at thread termination Read/write locks can be upgraded / downgraded Read/write locks do not favor writers Spawn API provides more POSIX-like process model C++ destructors and Pthread termination Unhandled exceptions terminate the thread (not the process) Exceptions vs. Asynchronous signals vs. ANSI C signals Mutexes can be named to aid in application debug
Unsupported APIs
Unsupported APIs
The following functions are not supported by the iSeries implementation of pthreads. These functions are all defined and provided by the system. You can create and compile with these functions in your application. If the unsupported functions are called, when the application runs the functions immediately fail with the ENOSYS error, and your application can take the appropriate action, such as ignoring the error and continuing.
q q q q q q q q q q q q q q q q
pthread_atfork()--Register Fork Handlers pthread_atfork_np()--Register Fork Handlers with Extended Options pthread_attr_getschedpolicy()--Get Scheduling Policy pthread_attr_getscope()--Get Scheduling Scope pthread_attr_getstackaddr()--Get Stack Address pthread_attr_getstacksize()--Get Stack Size pthread_attr_setschedpolicy()--Set Scheduling Policy pthread_attr_setscope()--Set Scheduling Scope pthread_attr_setstackaddr()--Set Stack Address pthread_attr_setstacksize()--Set Stack Size pthread_mutexattr_getprioceiling()--Get Mutex Priority Ceiling Attribute pthread_mutexattr_getprotocol()--Get Mutex Protocol Attribute pthread_mutexattr_setprioceiling()--Set Mutex Priority Ceiling Attribute pthread_mutexattr_setprotocol()--Set Mutex Protocol Attribute pthread_mutex_getprioceiling()--Get Mutex Priority Ceiling pthread_mutex_setprioceiling()--Set Mutex Priority Ceiling
Unsupported APIs
Syntax #include <pthread.h> #include <sched.h> int pthread_atfork(int *userstate, void (*prepare)(void), void (*parent)(void), void (*child)(void)); The pthread_atfork_np() function is not supported by this implementation. The function returns ENOSYS.
Unsupported APIs
Unsupported APIs
Unsupported APIs
ENOSYS.
Unsupported constants
Unsupported constants
The following constants related to threads are not defined on AS/400.
q q q q
An appropriate alternative to create cancellation points for these APIs might be like the following example. You can use this example to create a cancellation point out of any function that is asynchronous signal safe. See the Signal Concepts section of the Unix Type APIs section in the System API reference book for a list of functions that are asynchronous signal safe. If a function is not asynchronous signal safe, you should not use this form of asynchronous cancellation because it corrupt data.
Example
... preceding code ... int oldtype=0; /* If cancellation is currently disabled, this will have no effect */ /* if cancellation is currently enabled, we'll set it to asynchronous */ /* for the duration of this call to try to simulate a cancellation point */ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); /* Call kernel API that you want to be a cancel point. You should */ /* only call functions which are asynchronous signal safe in this block. */ /* Validating the asynchronous signal safety of the function will */ /* ensure that the asynchronous cancellation does not negatively */ /* affect the API or corrupt the data that the API uses */ APICallHere(); /* Restore the cancellation type that was previously in effect */ pthread_setcanceltype(oldtype, &oldtype); ... following code ...
_SC_THREAD_DESTRUCTOR_ITERATIONS _SC_THREAD_PRIORITY_SCHEDULING _SC_THREADS _SC_THREAD_ATTR_STACKADDR _SC_THREAD_ATTR_STACKSIZE _SC_THREAD_KEYS_MAX _SC_THREAD_PRIO_INHERIT _SC_THREAD_PRIO_PROTECT _SC_THREAD_PROCESS_SHARED _SC_THREAD_SAFE_FUNCTIONS _SC_THREAD_STACK_MIN _SC_THREAD_THREADS_MAX
The priority of a thread is specified as a number that represents the value that is added to the priority of the process. Changing the priority of the process affects the priority of all of the threads within that process. The default priority for a thread is DEFAULT_PRIO_NP, which is no change from the process priority. On AS/400, numerically lower priority values indicate higher priority with regard to scheduling. The pthread.h and sched.h header files define the priority constants in a way that is consistent with the threads standard, but opposite of priority specifications on AS/400. When you specify a priority of -99 in a call to pthread_setschedparam(), the priority of the target thread is lowered to the lowest possible value. For example, process P1 is at AS/400 priority 20 and contains a thread T1 that specifies a Pthread priority adjustment of -18. Process P2 is at AS/400 priority 25 and contains thread T2 that specifies a priority of -5. The result is that the system schedules the threads using the AS/400 priority for T1 as 38 and for T2 as 30. The thread scheduling is specified at a system level, and although process P2 runs at a lower priority ranking than process P1, thread T2 within process P2 runs at a higher priority ranking than thread T1 in process P1, and thus gets more processing resources.
Example
The following example shows the correct way to store and retrieve integer information in pointer variables. #define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" int main(int argc, char **argv) { void *status1 = __VOID(5); void *status2 = __VOID(999); if (status1 == NULL) { printf("Status1 pointer is NULL\n"); } else { printf("Status1 pointer is non-NULL\n"); } if (status1 == status2) { printf("Both status variables as pointers are equal\n"); } else { if (status1 < status2) { printf("Status1 is greater than status2\n"); } else { if (status1 < status2) { printf("Status1 is less then status2\n"); } else { printf("The pointers are unordered!\n"); } } } printf("Pointer values stored in status variables are:\n" " status1 = %.8x %.8x %.8x %.8x\n"
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/concep20.htm (1 of 2) [2/9/2001 2:06:32 PM]
" status2 = %.8x %.8x %.8x %.8x\n", status1, status2); printf("Integer values stored in status variables are:\n" " status1 = %d\n" " status2 = %d\n", __INT(status1), __INT(status2)); return; }
Output:
Status1 pointer is non-NULL Status1 is less then status2 Pointer values stored in status variables are: status1 = 80000000 00000000 00008302 00000005 status2 = 80000000 00000000 00008302 000003e7 Integer values stored in status variables are: status1 = 5 status2 = 999
void *threadfunc(void *parm) { pthread_id_np_t tid; #error "This is an ERROR." #error "The 'thread' variable is shared between threads" #error "and must be protected by a mutex." pthread_getunique_np(&thread, &tid); printf("Thread 0x%.8x %.8x started\n", tid); return NULL; } int main(int argc, char **argv) { int rc=0; printf("Enter Testcase - %s\n", argv[0]); #error "This is an ERROR." #error "The order of thread thread startup, and return from" #error "the pthread_create() API is NOT deterministic." rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create(NULL)\n", rc); /* sleep() isn't a very robust way to wait for the thread */ sleep(5); printf("Main completed\n"); return 0; }
If the initial thread calls pthread_exit(), the process terminates. If the initial thread is the target of a pthread_cancel() request that is acted upon, the process terminates. If the initial thread terminates through any other action, the process terminates. Many OS/400 APIs and commands target jobs. Some of those APIs target resources that are allocated to threads for retrieval or modification. If this is the case, the resources that displayed, modified, or retrieved may be the resources owned by the initial thread. For example, the CL command WRKACTJOB allows you to display information such as the call stack for a job. Since a job does not have a call stack and the call stack is thread scoped, the call stack of the initial thread is displayed when you choose to display the call stack of a job. Other APIs or CL commands that operate against jobs have undergone similar changes. See the specific documentation for the API or CL command of concern.
Not all jobs can create threads; pthread_create() fails with EBUSY
Not all jobs can create threads; pthread_create() fails with EBUSY
Because many parts of the operating system are not yet thread safe, not every AS/400 job is allowed to start threads. The pthread_create() API fails with the EBUSY error when the process is not allowed to create threads. See Running threaded programs for information about how to start a job that can create threads. For details about how to determine whether thread creation is currently allowed for your process, you can see the pthread_getpthreadoption_np() API, option PTHREAD_OPTION_THREAD_CAPABLE_NP. See Multithreaded Applications for an introduction to threads and general API information about AS/400 threads.
A thread can acquire any number of shared read locks on a read/write lock. Each successful shared read lock that is acquired must be released by a call to pthread_rwlock_unlock(). A thread can acquire any number of exclusive write locks on a read/write lock. Each successful exclusive write lock that is acquired must be released by a call to pthread_rwlock_unlock().
If a thread currently holds a shared read lock, an attempt by the same thread to acquire an exclusive write lock succeeds if no other threads hold a shared read lock. The thread then holds both an exclusive write lock and a shared read lock. If a thread currently holds an exclusive write lock, an attempt by the thread to acquire a shared read lock succeeds. The thread then holds both an exclusive write lock and a shared read lock. If a thread holds one or more shared read locks and one or more exclusive write locks on the same read/write lock object at the same time, a call to pthread_rwlock_unlock() always unlocks the exclusive write lock FIRST. When multiple exclusive write locks and multiple exclusive read locks are held by the same thread on the same read/write lock object, the behavior of pthread_rwlock_unlock() is as follows:
r
A call to the pthread_rwlock_unlock() function always unlocks the most recent exclusive write lock first. Subsequent calls to pthread_rwlock_unlock() first reduce the count of any outstanding exclusive write locks held by the thread until all exclusive write locks are unlocked. After all outstanding exclusive write locks are unlocked and the thread holds only shared read locks on the read/write lock object, a call to pthread_rwlock_unlock() function then unlocks the most recent shared read lock. Subsequent calls to pthread_rwlock_unlock() reduce the count of any outstanding shared read locks held by the thread until all shared read locks are unlocked.
For a thread to change a shared read lock to an exclusive write lock, the thread should perform the following actions: { pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; pthread_rwlock_rdlock(&rwlock); ... /* Thread holding a read lock decides it needs to upgrade to a write lock */ /* Now Upgrade to write lock */ pthread_rwlock_wrlock(&rwlock);
... /* write lock (and read lock) are held here.*/ /* We have effectively upgraded to a write lock */ ... /* `Downgrade' back to a only the read lock */ pthread_rwlock_unlock(&rwlock); ... /* unlock the read lock */ pthread_rwlock_unlock(&rwlock); } For a thread to change an exclusive write lock to a shared read lock, the thread should perform the following actions: { pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; pthread_rwlock_wrlock(&rwlock); .. /* Thread holding the write lock decides it needs to downgrade to a read lock */ /* Get the read lock, so we are holding BOTH read and write locks */ pthread_rwlock_rdlock(&rwlock); ... /* An unlock always unlocks the write lock first */ pthread_wrlock_unlock(&rwlock); ... /* At this point, we are only holding the read lock. */ /* We have effectively downgraded the write lock to a read lock */ ... /* Use unlock to unlock the last read lock. */ pthread_wrlock_unlock(&rwlock); }
A thread calls pthread_exit() or returns from the thread start routine. A thread is the target of pthread_cancel(). A thread is ended due to an unhandled exception. A thread is in a process that contains another thread that calls exit() or abort(). A thread is in a process that is terminated by the system administrator. A thread is being terminated by the system administrator.
When a thread terminates, the following occurs: 1. If the thread was ended using pthread_exit(), pthread_cancel() or return from the thread start routine, then cancellation cleanup handlers and data destructors are run. 2. The thread is terminated. At the time that the thread is terminated, both C++ destructors for automatic objects and AS/400 cancel handlers run. If a Pthread is terminated using a non-Pthread method (an AS/400 exception, a different thread termination primitive provided by the system, exit() or abort(), or other job termination method), Pthread cancellation cleanup handlers and data destructors do not run.
Example
This example shows the relationship between C++ destructors and Pthread cleanup mechanisms. #define _MULTI_THREADED #include <stdio.h> #include <qp0z1170.h> #include <time.h> #include <pthread.h> #include "check.h" #define bufferSize 100 #define threadRc 55 pthread_key_t void void void void void tlskey;
tid; buffer[bufferSize];
void dataDestructor(void *parm) { printf("In data destructor\n"); pthread_setspecific(tlskey, NULL); } void cancelHandler(void *parm) { printf("In cancellation cleanup handler\n"); } void *threadfunc(void *parm) { A object("start routine object"); level2(); return NULL; } void level2(void) { A object("Second level object"); level3(); } void level3(void) { int rc; struct timespec ts = {5, 0}; A object("Third level object"); pthread_setspecific(tlskey, &tlskey); pthread_cleanup_push(cancelHandler, NULL); printf("Thread blocked\n"); rc = pthread_delay_np(&ts); if (rc != 0) { printf("pthread_delay_np() - return code %d\n", rc); return; } printf("Calling pthread_exit()\n"); pthread_exit(__VOID(threadRc)); pthread_cleanup_pop(0); } int main(int argc, char **argv) { int rc=0; int i; pthread_t threadid; void *status; int fail=0; printf("Enter Testcase - %s\n", argv[0]); rc = pthread_key_create(&tlskey, dataDestructor); checkResults("pthread_key_create()\n", rc); printf("----------- Start pthread_cancel() example -------------\n"); printf("Create a thread\n"); rc = pthread_create(&threadid, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); sleep(2); rc = pthread_cancel(threadid); checkResults("pthread_cancel()\n", rc); rc = pthread_join(threadid, &status);
checkResults("pthread_join()\n", rc); if (status != PTHREAD_CANCELED) { printf("Canceled thread did not return the expected results\n"); fail = 1; } printf("----------- Start pthread_exit() example -------------\n"); printf("Create a thread\n"); rc = pthread_create(&threadid, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(threadid, &status); checkResults("pthread_join()\n", rc); if (__INT(status) != threadRc) { printf("pthread_exit() thread did not return the expected results\n"); fail = 1; } pthread_key_delete(tlskey); if (fail) { printf("At least one thread failed!\n"); exit(1); } printf("Main completed\n"); return 0; } A::A(char *label) { strncpy(buffer, label, bufferSize); pthread_t me; me = pthread_self(); pthread_getunique_np(&me, &tid); printf("`%s' instantiated in thread 0x%.8x %.8x\n", buffer, tid); } A::~A() { printf("`%s' destroyed in thread 0x%.8x %.8x\n", buffer, tid); }
Output:
Enter Testcase - QP0WTEST/TPCPP0 ----------- Start pthread_cancel() example ------------Create a thread `start routine object' instantiated in thread 0x00000000 00000161 `Second level object' instantiated in thread 0x00000000 00000161 `Third level object' instantiated in thread 0x00000000 00000161 Thread blocked In cancellation cleanup handler In data destructor `Third level object' destroyed in thread 0x00000000 00000161 `Second level object' destroyed in thread 0x00000000 00000161 `start routine object' destroyed in thread 0x00000000 00000161 ----------- Start pthread_exit() example ------------Create a thread `start routine object' instantiated in thread 0x00000000 00000162 `Second level object' instantiated in thread 0x00000000 00000162 `Third level object' instantiated in thread 0x00000000 00000162 Thread blocked
Calling pthread_exit() In cancellation cleanup handler In data destructor `Third level object' destroyed in thread 0x00000000 00000162 `Second level object' destroyed in thread 0x00000000 00000162 `start routine object' destroyed in thread 0x00000000 00000162 Main completed
Example
#define _MULTI_THREADED #include <stdio.h> #include <qp0z1170.h> #include <time.h> #include <signal.h> #include <pthread.h> #include "check.h" void abortTheProcessWhenAnExceptionOccurs(int sigNumber); void *threadfunc1(void *parm); void *threadfunc1(void *parm) { char *p=NULL; printf("Thread1: Unhandled exception (pointer fault) about to happen\n"); *p = `!'; printf("Thread1: After exception\n"); return NULL; }
void abortTheProcessWhenAnExceptionOccurs(int sigNumber) { /* In a multithreaded environment this is a little difficult. We have to */ /* re-enable the ANSI C handler immediately, because that is the way it */ /* is defined. (A better alternative may be direct monitor exception */ /* handlers that are always valid in the function which they are */ /* registered, and with direct monitors, we can catch the hardware */ /* exception before it is converted to an ANSI C signal */ signal(SIGALL, abortTheProcessWhenAnExceptionOccurs); /* Since ANSI C signals and hardware exceptions are only handled in */ /* the same thread that caused them, we send the Posix signal to */ /* the calling thread (The signal is delivered before returning from */ /* pthread_kill(). */ printf("Mapping ANSI signal %d to posix signal SIGABRT. " "Aborting the process\n", sigNumber); /* If we want to do some debug processing, we can put it here. */ pthread_kill(pthread_self(), SIGABRT); return; } int main(int argc, char **argv) { int rc=0; pthread_t threadid; void *status; printf("----------- Setup Signal Mapping/Handling -------------\n"); printf("- Register ANSI C signal handler to map ALL\n" " ANSI C signals & hardware exceptions to Posix signals\n"); /* If we want to do debug, or determine what when wrong a little more easily, */ /* we could use the abortTheProcessWhenAnExceptionOccurs function to delay the thread, or */ /* dump failure data of some sort. */ signal(SIGALL, abortTheProcessWhenAnExceptionOccurs); printf("----------- Start memory fault thread -------------\n"); printf("Create a thread\n"); rc = pthread_create(&threadid, NULL, threadfunc1, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(threadid, &status); checkResults("pthread_join()\n", rc); printf("Main completed\n"); return 0;
Output:
----------- Setup Signal Mapping/Handling ------------- Register ANSI C signal handler to map ALL ANSI C signals & hardware exceptions to Posix signals ----------- Start memory fault thread ------------Create a thread Thread1: Unhandled exception (pointer fault) about to happen Mapping ANSI signal 5 to posix signal SIGABRT. Aborting the process
Example
#define _MULTI_THREADED #include <stdio.h> #include <qp0z1170.h> #include <time.h> #include <signal.h> #include <pthread.h> #include "check.h" void myAnsiSignalMapperHdlr(int sigNumber); void *threadfunc1(void *parm); void *threadfunc2(void *parm);
void *threadfunc1(void *parm) { char *p=NULL; printf("Thread1: Unhandled exception (pointer fault) about to happen\n"); *p = `!'; printf("Thread1: After exception\n"); return NULL; } void *threadfunc2(void *parm) { int i1=0, i2=1, i3=0; printf("Thread2: Unhandled exception (divide by zero) about to happen\n"); i1 = i2 / i3; printf("Thread2: After exception\n"); return NULL; } void myAnsiSignalMapperHdlr(int sigNumber) { /* In a multithreaded environment, this is slightly difficult. We have to*/ /* re-enable the ANSI C handler immediately, because that is the way it */ /* is defined. (A better alternative may be direct monitor exception */ /* handlers which are always valid in the function which they are */ /* registered, and with direct monitors, we can catch the hardware */ /* exception before it is converted to an ANSI C signal */ signal(SIGALL, myAnsiSignalMapperHdlr); /* Since ANSI C signals and hardware exceptions will only be handled in */ /* the same thread that caused them, we will send the POSIX signal to */ /* the calling thread (The signal will be delivered before returning from */ /* pthread_kill(). */ printf("Mapping ANSI signal to POSIX signal %d\n", sigNumber); pthread_kill(pthread_self(), sigNumber); return; } void fpViolationHldr(int sigNumber) { printf("Thread 0x%.8x %.8x " "Handled floating point failure SIGFPE (signal %d)\n", pthread_getthreadid_np(), sigNumber); /* By definition, returning from a POSIX signal handler handles the signal*/ } void segFaultHdlr(int sigNumber) { printf("Thread 0x%.8x %.8x " "Handled segmentation violation SIGSEGV (signal %d)\n", pthread_getthreadid_np(), sigNumber); /* By definition, returning from a POSIX signal handler handles the signal*/ }
int main(int argc, char **argv) { int rc=0; pthread_t threadid; struct sigaction actions; void *status; printf("----------- Setup Signal Mapping/Handling -------------\n"); printf("- Register ANSI C signal handler to map ALL\n" " ANSI C signals & hardware exceptions to POSIX signals\n"); signal(SIGALL, myAnsiSignalMapperHdlr); printf("- Register normal POSIX signal handling mechanisms\n" " for floating point violations, and segmentation faults\n" "- Other signals take the default action for asynchronous signals\n"); memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = fpViolationHldr; rc = sigaction(SIGFPE,&actions,NULL); checkResults("sigaction for SIGFPE\n", rc); actions.sa_handler = segFaultHdlr; rc = sigaction(SIGSEGV,&actions,NULL); checkResults("sigaction for SIGSEGV\n", rc); printf("----------- Start memory fault thread -------------\n"); printf("Create a thread\n"); rc = pthread_create(&threadid, NULL, threadfunc1, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(threadid, &status); checkResults("pthread_join()\n", rc); printf("----------- Start divide by 0 thread -------------\n"); printf("Create a thread\n"); rc = pthread_create(&threadid, NULL, threadfunc2, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(threadid, &status); checkResults("pthread_join()\n", rc); printf("Main completed\n"); return 0; }
Example Output
----------- Setup Signal Mapping/Handling ------------- Register ANSI C signal handler to map ALL ANSI C signals & hardware exceptions to POSIX signals - Register normal POSIX signal handling mechanisms for floating point violations, and segmentation faults - Other signals take the default action for asynchronous signals ----------- Start memory fault thread ------------Create a thread Thread1: Unhandled exception (pointer fault) about to happen Mapping ANSI signal to POSIX signal 5
Thread 0x00000000 00000022 Handled segmentation violation SIGSEGV (signal 5) Thread1: After exception ----------- Start divide by 0 thread ------------Create a thread Thread2: Unhandled exception (divide by zero) about to happen Mapping ANSI signal to POSIX signal 2 Thread 0x00000000 00000023 Handled floating point failure SIGFPE (signal 2) Thread2: After exception Main completed The following example shows how a divide by zero error, and a dereference of a pointer that is not valid might be mapped to generate a POSIX (asynchronous) signal. This example uses AS/400 exception handlers to perform the signal mapping.
Example
#define _MULTI_THREADED #include <stdio.h> #include <stdlib.h> #include <qp0z1170.h> #include <time.h> #include <signal.h> #include <except.h> #include <qusec.h> /* System API error Code structure */ #include <qmh.h> /* Message Hanlder common defs */ #include <qmhchgem.h> /* Change exception message */ #include <pthread.h> #include "check.h" void myHardwareExceptionMapper(_INTRPT_Hndlr_Parms_T *exception); void *threadfunc1(void *parm); void *threadfunc2(void *parm); void *threadfunc1(void *parm) { char *p=NULL; /* Watch for all ESCAPE type exceptions. Other types may be used for */ /* job log messages or C++ exceptions or other control flow in the process*/ /* Adjust the message type as required by your application. */ #pragma exception_handler (myHardwareExceptionMapper, 0, _C1_ALL, _C2_MH_ESCAPE) printf("Thread1: Unhandled exception (pointer fault) about to happen\n"); *p = `!'; printf("Thread1: After exception\n"); #pragma disable_handler return NULL; } void *threadfunc2(void *parm) { int i1=0, i2=1, i3=0; /* Watch for all ESCAPE type exceptions. Others types may be used for */ /* job log messages or C++ exceptions or other control flow in the process*/ /* Adjust the message type as required by your application.
file:///y|/dv2k/shadow/dev2000/usertech/v5r1/cur/cmvc/doc2924.mri/apis/concep31.htm (4 of 7) [2/9/2001 2:06:35 PM]
*/ #pragma exception_handler (myHardwareExceptionMapper, 0, _C1_ALL, _C2_MH_ESCAPE) printf("Thread2: Unhandled exception (divide by zero) about to happen\n"); i1 = i2 / i3; printf("Thread2: After exception\n"); #pragma disable_handler return NULL; } void myHardwareExceptionMapper(_INTRPT_Hndlr_Parms_T *exInfo) { int sigNumber; Qus_EC_t errorCode = {0}; /* system API error structure */ printf("Handling system exception\n"); /* The exception information is available inside the exInfo structure */ /* for this example, we are going to handle all exceptions and then map */ /* them to an \Qappropriate' signal number. We are allowed to decide the */ /* signal mapping however is appropriate for our application. */ if (!memcmp(exInfo->Msg_Id, "MCH3601", 7)) { sigNumber = SIGSEGV; } else if (!memcmp(exInfo->Msg_Id, "MCH1211", 7)) { sigNumber = SIGFPE; } else { printf("Unexpected exception! Not Handling!\n"); abort(); } /* Even if the exception is \Qexpected', we are going to handle it and try */ /* to deliver it as a POSIX signal. Note that we SHOULD NOT HANDLE */ /* exceptions that are unexpected to us. Most code cannot tolerate */ /* getting back into it once the exception occured, and we could get into*/ /* a nice exception loop. */ /* See the system API reference for a description of QMHCHGEM */ QMHCHGEM(&exInfo->Target, 0, &exInfo->Msg_Ref_Key, QMH_MOD_HANDLE, (char *)NULL, 0, &errorCode); if (errorCode.Bytes_Available != 0) { printf("Failed to handle exception. Error Code = %7.7s\n", errorCode.Exception_Id); return; } printf("Mapping Exception %7.7s to POSIX signal %d\n", exInfo->Msg_Id ,sigNumber); /* At this point the exception is handled. If the POSIX signal handler */ /* returns, then the signal will be handled, and all will be complete */ pthread_kill(pthread_self(), sigNumber);
return; } void fpViolationHldr(int sigNumber) { printf("Thread 0x%.8x %.8x " "Handled floating point failure SIGFPE (signal %d)\n", pthread_getthreadid_np(), sigNumber); /* By definition, return from a POSIX signal handler handles the signal */ } void segFaultHdlr(int sigNumber) { printf("Thread 0x%.8x %.8x " "Handled segmentation violation SIGSEGV (signal %d)\n", pthread_getthreadid_np(), sigNumber); /* By definition, returning from a POSIX signal handler handles the signal*/ } int main(int argc, char **argv) { int rc=0; pthread_t threadid; struct sigaction actions; void *status; printf("----------- Setup Signal Mapping/Handling -------------\n"); printf("- The threads will register AS/400 Exception handler to map\n" " hardware exceptions to POSIX signals\n"); printf("- Register normal POSIX signal handling mechanisms\n" " for floating point violations, and segmentation faults\n" "- Other signals take the default action for asynchronous signals\n"); memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = fpViolationHldr; rc = sigaction(SIGFPE,&actions,NULL); checkResults("sigaction for SIGFPE\n", rc); actions.sa_handler = segFaultHdlr; rc = sigaction(SIGSEGV,&actions,NULL); checkResults("sigaction for SIGSEGV\n", rc); printf("----------- Start memory fault thread -------------\n"); printf("Create a thread\n"); rc = pthread_create(&threadid, NULL, threadfunc1, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(threadid, &status); checkResults("pthread_join()\n", rc); printf("----------- Start divide by 0 thread -------------\n"); printf("Create a thread\n"); rc = pthread_create(&threadid, NULL, threadfunc2, NULL); checkResults("pthread_create()\n", rc); rc = pthread_join(threadid, &status); checkResults("pthread_join()\n", rc);
Output
----------- Setup Signal Mapping/Handling ------------- The threads will register AS/400 Exception handler to map hardware exceptions to POSIX signals - Register normal POSIX signal handling mechanisms for floating point violations, and segmentation faults - Other signals take the default action for asynchronous signals ----------- Start memory fault thread ------------Create a thread Thread1: Unhandled exception (pointer fault) about to happen Handling system exception Mapping Exception MCH3601 to POSIX signal 5 Thread 0x00000000 00000024 Handled segmentation violation SIGSEGV (signal 5) Thread1: After exception ----------- Start divide by 0 thread ------------Create a thread Thread2: Unhandled exception (divide by zero) about to happen Handling system exception Mapping Exception MCH1211 to POSIX signal 2 Thread 0x00000000 00000025 Handled floating point failure SIGFPE (signal 2) Thread2: After exception Main completed
The header files are provided in the QSYSINC library which can be installed as an option. Make sure QSYSINC is on your system before compiling programs that use these header files. In release Version 4 Release 2, these header files are available on your system only if you have also loaded and applied the limited availability program temporary fix (PTF) or I-Listed programming request for price quotation (PRPQ) that provides the header file support. The PTF number is 5769SS1-J664741. The I-Listed PRPQ is "5799-XTH, IBM Pthread Kernel API's for AS/400", number P84311. Where to Find Header Files Name of Header File Name of File in QSYSINC Name of Member pthread.h H PTHREAD sched.h H SCHED
You can display a header file in QSYSINC by using one of the following methods:
q
Use your editor. For example, to display the pthread.h header file using the Source Entry Utility editor, enter the following command: STRSEU SRCFILE(QSYSINC/H) SRCMBR(PTHREAD) OPTION(5) Use the Display Physical File Member command. For example, to display the sched.h header file, enter the following command: DSPPFM FILE(QSYSINC/H) MBR(SCHED)
You can print a header file in QSYSINC by using one of the following methods:
q
Use your editor. For example, to print the pthread.h header file using the Source Entry Utility editor, enter the following command: STRSEU SRCFILE(QSYSINC/H) SRCMBR(PTHREAD) OPTION(6) Use your Copy File command. For example, to print the sched.h header file, enter the following command: CPYF FROMFILE(QSYSINC/H) TOFILE(*PRINT) FROMMBR(SCHED)
Pthread glossary
Pthread glossary
A
attribute object Any of the Pthreads data structures that are used to specify the initial states when creating certain resources (threads, mutexes, and condition variables). A thread attribute object can be used to create a thread. A mutex attributes object can be used to create a mutex. A condition attributes object can be used to create a condition. Functions that create attribute objects are pthread_attr_init(), pthread_mutexattr_init(), and pthread_condattr_init().
C
cancel A cancel is delivered to a thread when pthread_cancel() is issued and stops a thread. A cancel can be held pending if the target thread has cancellation DISABLED or DEFERRED. The cancel may be acted upon when cancellation is set to ENABLED or ASYNCHRONOUS. cancellation cleanup handler A function registered to perform some cleanup action. Cancellation cleanup handlers are called if a thread calls pthread_exit() or is the target of a pthread_cancel(). Cancellation cleanup handlers are stacked onto a cancellation cleanup stack and can be pushed and popped using the pthread_cleanup_push() and pthread_cleanup_pop() functions. cancellation point A function that causes a pending cancel to be delivered if the cancellation state is ENABLED, and the cancellation type is DEFERRED. pthread_testcancel() can be used to create a cancellation point. For a list of other functions that are cancellation points, see pthread_cancel(). cancellation state Either of two values (ENABLED or DISABLED) that describe whether cancels in the current thread are acted upon or held pending, If ENABLED, the cancellation is acted upon immediately based on the current cancellation type. If DISABLED, the cancel is held pending until it is ENABLED. You can modify the cancellation state using the pthread_setcancelstate() function. cancellation type Either of two values (DEFERRED or ASYNCHRONOUS) that describe how cancels are acted upon in the current thread when the cancellation state is ENABLED. If DEFERRED, the cancel is held pending, if ASYNCHRONOUS, the cancel is acted upon immediately, thus ending the thread with a status of PTHREAD_CANCELED. You can modify the cancellation type using the pthread_setcanceltype() function. condition variable An abstraction that allows a thread to wait for an event to occur. The condition variable is used with a Boolean predicate that indicates the presence or absence of the event and a mutex that protects both the predicate and the resources associated with the event. The condition variable has no ownership associated with it. See pthread_cond_init(), and other functions whose names begin with pthread_cond_.
D
detach a thread To mark a thread so that the system reclaims the thread resources when the thread ends. If the thread has already ended, the resources are freed immediately. After a thread's resources are freed, the exit status is no longer available, and the thread cannot be detached or joined to. Use the pthread_attr_setdetachstate(), or pthread_detach() functions to detach a thread, or the pthread_join() function to wait for and then detach a
Pthread glossary
thread.
E
exit status The return value from a thread. A variable of type void *, which typically contains some pointer to a control block pointer or return value, that shows under what conditions the thread ended. The thread can be ended and the exit status can be set by returning from the thread start routine, by calling pthread_exit(), or by canceling a thread using pthread_cancel().
G
global mutex A single mutex that is stored globally to the process that is provided by the pthreads library to allow easy serialization (a mechanism that allows only one thread to act at one time) to application resources. See the functions pthread_lock_global_np() or pthread_unlock_global_np().
I
initial thread The thread that is started automatically by the system when a job or process is started. Every job has at least one thread. That thread is often referred to as the initial thread or the primary thread. Threads other than the initial thread are referred to as secondary threads. If the initial thread ends, it causes all secondary threads and the job to end. See also `Secondary thread'.
J
join to a thread To wait for a thread to complete, detach the thread, and optionally return its exit status. Use pthread_join() to wait for a thread to complete.
M
main thread See initial thread. multithread capable This term is specific to AS/400. See thread capable. multithreaded A process that has multiple active threads. In the AS/400 documentation, the term multithreaded is sometimes used as a synomym for multithread capable. mutex An abstraction that allows two or more threads to cooperate in a MUTual EXclusion protocol that allows safe access to shared resources. See pthread_mutex_init() or other functions whose names begin with pthread_mutex_. Also see recursive mutex, named mutex, global mutex.
Pthread glossary
N
named mutex A mutex with an associated text name used for identification and debugging. The name is used in some system dumps and debug or thread-management user interfaces. The name does not affect the behavior of the mutex, only the ability to debug the use of that mutex. The Pthread run-time names all mutexes by default. See the functions pthread_mutexattr_setname_np() or pthread_mutexattr_getname_np().
O
orphaned mutex A mutex that was held by a thread when that thread ended. Any application data or resources associated with the mutex are most likely in an inconsistent state if a mutex is orphaned. An orphaned mutex is not available to be locked by another thread and causes a locking thread to block indefinitely or to get the EBUSY error when attempting to trylock the mutex.
P
POSIX thread handle The pthread_t data type that is returned to a creator of a POSIX thread. The pthread_t represents an opaque handle to the POSIX thread. It should not be modified except through the use of the pthread functions. The pthread_create() or pthread_self() function returns the POSIX thread handle. The pthread_equal() function can be used to confirm whether two handles refer to the same thread. The POSIX thread handle is sometimes referred to as the thread ID. primary thread See initial thread. Pthread Shorthand for POSIX or Single Unix Specification Thread, as in 'the interfaces described in this document are based on the POSIX standard (ANSI/IEEE Standard 1003.1, 1996 Edition OR ISO/IEC 9945-1: 1996) and the Single UNIX Specification, Version 2, 1997'.
R
recursive mutex A mutex that can be acquired again by the owning thread. A recursive mutex does not become unlocked until the number of unlock requests equals the number of successful lock requests. A non-recursive (i.e., normal) mutex causes an EDEADLK error if an attempt is made by the owning thread to lock it a second time. See the functions pthread_mutexattr_setkind_np() or pthread_mutexattr_getkind_np().
S
scheduling parameters Information describing the scheduling characteristics of a thread. The sched_param structure contains scheduling parameters. On AS/400, the scheduling parameters allow you to only specify the priority of the thread. Scheduling Policy is restricted to the proprietary AS/400 scheduling policy. Use the pthread_attr_setschedparam(), pthread_attr_getschedparam(), pthread_setschedparam(), or pthread_getschedparam() functions to manipulate scheduling parameters. scheduling policy
Pthread glossary
Information describing which algorithm is used to schedule threads within the process or system. Some scheduling policies are Round Robin or FIFO. AS/400 uses the SCHED_OTHER constant to indicate the delay cost scheduling that the system uses. The scheduling parameter functions support only the SCHED_OTHER policy, and the pthread_attr_getschedpolicy() and pthread_attr_setschedpolicy() functions are not supported. scope Information describing whether the scheduling policy indicates that threads compete directly with other threads within the process or the system. AS/400 schedules threads within the system, and the pthread_attr_setscope() and pthread_attr_getscope() functions are not supported. secondary thread Any thread started by or on behalf of the application that is not the initial thread. Secondary threads are started by invoking pthread_create() or another library service that creates threads. Secondary threads have no parent/child relationship. signal An asynchronous mechanism for interrupting the processing of a thread. The system delivers a signal to a thread when the application programmer takes explicit or implicit action to cause the signal to be delivered. The signal can be sent to a thread or process, but is always delivered to a specific thread. signal handler A function registered by the application programmer that the system executes when a signal is delivered to a thread. The function runs immediately in the thread, interrupting any application processing that is in progress. signal safe A function, macro or operating system service that can be called safely from a signal handler. The function always acts in a well-defined manner. It does not rely on any external state or locks that might be in an inconsistent state at the time the signal handler function is invoked by the system. signal unsafe A function, macro or operating system service that cannot be called safely from within a signal handler. A signal unsafe function may acquire locks or otherwise change the state of a resource. When the signal is delivered to the thread, the signal handler runs. The state of the resource or the lock managed by the signal unsafe function is unknown because it was interrupted by the signal before it completed. If the signal unsafe function is called again, the results are non-deterministic.
T
thread An independent sequence of execution of program code and processing context inside a process. A unique unit of work or flow of control within a process. A thread runs a procedure asynchronously with other threads running the same or different procedures within the process. All threads within a process equally share activation group and process resources (Heap storage, static storage, open files, socket descriptors, other communications ports, environment variables, etc.). A thread has few resources (mutexes, locks, automatic storage, thread specific storage) that are not shared. On a multiprocessor system, multiple threads in a process can run concurrently. thread capable job On AS/400, the only job that can create threads. Certain system behavior and the architecture of the process changes slightly to support AS/400 threads. If a job is not thread capable, attempts to create a thread result in the EBUSY error. You can create a thread capable process by using the spawn() interface or by using other AS/400 job-creation commands that allow you to specify that the new job should be thread capable. thread ID The unique integral number can be used to identify the thread. This integral number is available for retrieval via the pthread_getunique_np() interface. Although no Pthread interfaces use the integral thread ID to identify a thread for manipulation, thread ID is sometimes used to describe the pthread_t data type that represents the abstraction to a thread. See POSIX thread handle.
Pthread glossary
thread local storage (TLS) See thread specific storage. threadsafe A function, macro or operating system service that can be called from multiple threads in a process at the same time. The function always acts in a well-defined manner. The end results are as if the function was called by each thread in turn, even though all of the threads were running the function at the same time. Some APIs have restrictions about how they can be called in order for them to be thread safe. See the API documentation for all APIs or system services that you use in a multithreaded job. thread specific storage Storage that is not shared between threads, but that can be accessed by all functions within that thread. Usually, thread specific storage is indexed by a key. The key is a global value visible to all threads, and it is used to retrieve the thread-specific value of the storage associated with that key. Also called thread private storage, thread local storage or TLS. See the pthread_getspecific(), pthread_setspecific(), pthread_key_create(), and pthread_key_delete() functions. thread unsafe A function, macro, or operating system service that cannot be called from multiple threads is called thread unsafe. If this function is used in multiple threads or in a process that has multiple threads active, the results are undefined. A thread unsafe function can corrupt or negatively interact with data in another function (thread safe or otherwise) that appears to be unrelated to the first function. Do NOT use thread unsafe functions in your multithreaded application. Do NOT call programs or service programs that use thread-unsafe functions. See the API documentation for all APIs or system services that you use in a multithreaded job.
"Programming with POSIX Threads" by David R. Butenhof, ISBN#: 0201633922 "Threads Primer: A Guide to Solaris Multithreaded Programming " by Bil Lewis and Daniel J. Berg, Prentice Hall, ISBN#: 0134436989 The following standards are the base reference documents that the APIs in this section have originated from.
r r
ANSI/IEEE 1003.1 1996 (A.K.A. ISO/IEC 9945-1 1996) The Single Unix Specification, Version 2, 1997
Ensure that all of the APIs or system services that you use are threadsafe. See the Multithreaded applications for an introduction to threads and general information about AS/400 threads. Insert the following lines into any module that uses the thread data types or definitions. #define _MULTI_THREADED #include <pthread.h> The preprocessor definition _MULTI_THREADED must come before the pthread.h. See Header files for Pthread functions for more information on header files. See Using the _MULTI_THREADED preprocessor definition for more information on the _MULTI_THREADED preprocessor definition.
Compile the program normally; use the CRTCMOD followed by the CRTPGM or CRTSRVPGM commands. You can also use the CRTBNDC CL command to create your threaded program. Since Pthread APIs can operate on functions and data which could exist in different compilation units (modules), the same storage model and data model must be used throughout all compilation units within a program or service program that uses Pthread APIs. Otherwise, unpredictable behavior and failures will occur. Refer to "iSeries ILE Concepts V5R1" chapter 4 "Teraspace and single-level store" for more information on storage model and data model.
Use the OS/400 QShell Interpreter. In the QShell Interpreter, a program gets descriptors 0, 1, and 2 as the standard files; the parent and child I/O is directed to the console. The QShell interpreter allows you to run multithreaded programs as if they were interactive. See Qshell Interpreter for a description of the QIBM_MULTI_THREADED shell variable, which, when set to 'Y', allows you to run multithreaded programs the same way you run any other program. The QShell Interpreter is option 30 of Base OS/400. Use the spawn() API. The spawn() API has a flag in the spawn inheritance structure that allows you to turn on the multithread capability for the child job. The QUSRTOOL library also provides source code and an example CL command to allow you to create and use a SPAWN CL command in a way that is similar to the SBMJOB CL command. See the SPAWN CL command, QUSRTOOL example for more information. Use the SBMJOB CL command. Setting the 'Allow multiple threads' parameter (keyword ALWMLTTHD) on the CL command allows you to turn on the multithread capability of the submitted job. Use the CRTJOBD CL command to create a special job description; then create your job using a mechanism that will use the job description. Setting the 'Allow multiple threads' parameter (keyword ALWMLTTHD) on the job description allows you to turn on the multithread capability of the jobs that are created using that job description.
Cannot find header files pthread.h or qp0ztype.h or qp0zptha.h Thread creation (pthread_create()) fails with EBUSY or 3029 Mixing thread models or API sets Reserved fields must be binary zero Powerful OS/400 cleanup mechanisms allow application deadlock (cancel_handler and C++ automatic destructors) Thread creation using C++ methods as target does not work MCH3402 from pointer returned by pthread_join()
q q
If you get failure messages similar to the following: KULACK/QCSRC/MYPGM line 5: Unable to find #include file *LIBL/H(PTHREAD). you might have one of two problems:
r
Either your system does not have the C header files for openness (the QSYSINC library) installed, you are on a Version 4 Release 2 system and you do not have the PTF installed (PTF number 5769SS1-J664741) that provides the Pthread header files. Your compile command is not searching the correct locations for system header files. Install the Openness includes (System Openness Includes, 5769-SS1 Option 3) and the QSYSINC library, install the PTF support (PTF number 5769SS1-J664741) for kernel threads header files. Correct your search paths or library list.
r q
If you get failure messages similar to the following: QSYSINC/H/PTHREAD line 48: Unable to find #include file QCPA/H(PTHREAD). QSYSINC/H/PTHREAD line 60: #error "#ifndef _MULTI_THREADED" QSYSINC/H/PTHREAD line 61: #error "#ifndef QP0Z_CPA_THREADS_PRESENT" you have forgotten to define the _MULTI_THREADED preprocessor symbol. Use the C preprocessor statement `#define _MULTI_THREADED' in your application, or define _MULTI_THREADED on the CRTCMOD or other compile command that you use to compile your modules. Because the CPA toolkit supported threads before kernel threads being introduced on AS/400, if you do not define _MULTI_THREADED when compiling your C modules, the system attempts to compile your application using the CPA header files. The recommended threads model is kernel threads. You must define _MULTI_THREADED when you compile your application.
If you get failure messages similar to the following: QCPA/H/PTHREAD line 171: Unable to find #include file *LIBL/H(QP0ZTYPE). QCPA/H/PTHREAD line 183: Unable to find #include file *LIBL/H(QP0ZPTHA). you have forgotten to define the _MULTI_THREADED preprocessor symbol. Use the C preprocessor statement #define _MULTI_THREADED in your application, or define _MULTI_THREADED on the CRTCMOD or other compile command that you use to compile your modules. Because the CPA toolkit supported threads prior to kernel threads being introduced on AS/400, if you do not define _MULTI_THREADED when compiling your C modules, the system attempts to compile your application using the CPA header files. The recommended threads model is kernel threads. You must define _MULTI_THREADED when you compile your application.
Powerful OS/400 cleanup mechanisms allow application deadlock (cancel_handler and C++ automatic destructors)
Powerful OS/400 cleanup mechanisms allow application deadlock (cancel_handler and C++ automatic destructors)
AS/400 provides a set of powerful cleanup mechanisms. In OS/400, an application has the ability to register a cancel handler. Your application can enable a cancel handler by using the #pragma cancel_handler preprocessor statement if it is written in C or C++ or by using the CEERTX() API. A cancel handler is similar to a Pthread cancellation cleanup handler. However, a cancel handler runs whenever the stack frame or function for which it was registered ends in any way other than a normal return. Pthread cancellation cleanup handlers run only when the thread is terminated with pthread_exit() or pthread_cancel() or when the thread returns from the threads start routine. The cancel handler is guaranteed to run for all conditions that cause the stack frame to end (other than return), such as thread termination, job termination, calls to exit(), abort(), exceptions that percolate up the stack, and cancel stack frames. Similarly, C++ destructors for automatic C++ objects are guaranteed to run when the stack frame (function) or scope in which it was registered ends. These mechanisms ensure that your application can always clean up its resources. With the added power of these mechanisms, an application can easily cause a deadlock. The following is an example of such a problem. An application has a function foo() that registers a cancel handler called cleanup(). The function foo() is called by multiple threads in the application. The application is ended abnormally with a call to abort() or by system operator intervention (with the ENDJOB *IMMED CL command). When this job is ended, every thread is immediately terminated. When the system terminates a thread by terminating each call stack entry in the thread, it eventually reaches the function foo() in that thread. When function foo() is reached, the system recognizes that it must not remove that function from the call stack without running the function cleanup(), and so the system runs cleanup(). Because your application is multithreaded, all of the job ending and cleanup processing proceeds in parallel in each thread. Also, because abort() or ENDJOB *IMMED was used, the current state and location of each thread in your application is cannot be determined. When the cleanup() function runs, it is very difficult for the application to correctly assume that any specific cleanup can be done. Any resources that the cleanup() function attempts to acquire may be held by other threads in the process, other jobs in the system, or possibly by the same thread running the cleanup() function. The state of application variables or resources that your application manipulates may be in an inconsistent state because the call to abort() or ENDJOB *IMMED asynchronously interrupted every thread in the process at the same time. The application can easily reach a deadlock when running the cancel handlers or C++ destructors. Do not attempt to acquire locks or resources in cancel handlers or C++ automatic object destructors without preparing for the possibility that the resources cannot be acquired.
Important
Neither a cancel handler nor a destructor for a C++ object can prevent the call stack entry from being terminated, but the termination of the call stack entry (and therefore the job or thread) is delayed until the cancel handler or destructor completes. If the cancel handler or destructor does not complete, the system does not continue terminating the call stack entry (and possibly the job or thread). The only alternative at this point is to use the WRKJOB CL command (option 20) to end the thread, or the ENDJOB *IMMED CL command. If the ENDJOB *IMMED command causes a cancel handler to run in the first place, the only option left is the ENDJOBABN CL command because any remaining cancel handlers are still guaranteed to run. The ENDJOBABN CL command is not recommended. The ENDJOBABN command causes the job to be terminated with no further cleanup allowed (application or operating system). If the application is suspended while trying to access certain operating system resources, those resources may be damaged. If operating system resources are damaged, you may need to take various reclaim, deletion, or recovery steps and, in extreme conditions, restart the system.
Powerful OS/400 cleanup mechanisms allow application deadlock (cancel_handler and C++ automatic destructors)
Recommendations
If you want to cleanup your job or application, you can use one of the following mechanisms:
q
If you want to do process level or activation group cleanup for normal termination, use the C atexit() function to register your cleanup function. The atexit() function provides a mechanism to run cleanup after the activation group and possibly the threads, are terminated. This action significantly reduces the complexity. If you always want a chance to do process level or activation group cleanup in all cases (normal and abnormal), you could use the Register Activation Group Exit (CEE4RAGE()) system API. The CEE4RAGE() function provides a mechanism to run cleanup after the activation group (and possibly the threads) are terminated. This action significantly reduces the complexity. You can safely use cancel handlers. Simplify your cancel handlers so that they only unlock or release resources and do not attempt to acquire any new resources or locks. You can remove your cancel handlers and create a CL command, program, or tool that terminates your application in a more controlled fashion:
r
One possibility is a tool that uses a signal to terminate the application. When the signal comes in, your application can get control in a single location (preferably by using the sigwait() API to safely and synchronously get the signal), and then perform some level of cleanup. Then it can use exit() or abort() to end the application from within. Often this action is sufficient to remove the complexity. A second possibility is to use the ENDJOB *CNTRLD CL command and have your application dedicate a thread to watching for the controlled end condition. The application thread can use the QUSRJOBI (Get Job Information) or the QWCRTVCA (Retrieve Current Attributes) APIs to look at the End Status information associated with your job. The End Status indicates that the job is ending in a controlled fashion, and your application can take safe and synchronous steps to clean up and exit. A third possibility is to use the asynchronous signals support and set up a handler for the SIGTERM asynchronous signal. Support has been added to the system so that, if an ENDJOB *CNTRLD is done and the target job has a handler registered for the SIGTERM signal, that signal gets delivered to the target job. You should dedicate a thread for handling signals by using the sigwait() API in the dedicated thread. When the signal handling thread detects a SIGTERM signal using the sigwait() API, it can safely clean up and terminate the application. The system support for the delivery of the SIGTERM signal when ENDJOB *CNTRLD is issued was added in the base OS/400 in Version 4 Release 3 Modification 0 and is also available in Version 4 Release 2 Modification 0 via program temporary fixes (PTFs) 5769SS1-SF47161 and 5769SS1-SF47175. For more information about ending your job, see the Work Management topic.. A fourth possibility includes other interprocess communications (IPC) mechanisms that can also be used to indicate that your application should terminate in a safe and controlled fashion.
If you want to do thread-level cleanup, use the pthread APIs, such as pthread_cleanup_push(), pthread_cleanup_pop(), and pthread_key_create() to create cancellation cleanup functions that run when the thread terminates under normal conditions. Often your cleanup functions do not need to run when the job ends. The most common use for these functions is to free heap storage or unlock resources. Unlocking resources is safe in a cancel handler, and you do not need to use free() on heap storage when the entire job is ending anyway.
Example
/* This C++ example must be compiled with VisualAge C++ for OS/400 */ #define _MULTI_THREADED #include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <pthread.h> class ThreadClass { public: ThreadClass(char *s) { data1 = 42; data2 = strlen(s); strncpy(str, s, sizeof(str)-1); str[49]=0; } void *run(void); private: int data1; int data2; char str[50]; }; extern "C" void *ThreadStartup(void *); int main(int argc, char **argv) { ThreadClass *t=NULL; pthread_t thread; int rc; // Use printf instead of cout. // At the time this test was written, the C++ standard class library // was not thread safe. printf("Entered test %s\n", argv[0]); printf("Create a ThreadClass object\n"); t = new ThreadClass("Testing C++ object/thread creation\n"); printf("Start a real thread to process the ThreadClass object\n"); // #define COMPILE_ERROR #ifdef COMPILE_ERROR
// // // // // //
This is an ERROR. You cannot create a thread by using a pointer to a member function. Thread creation requires a C linkage function. If you remove the comments from the line `#define COMPILE_ERROR' the compiler will give a message similar to this: "ATESTCPP0.C", line 46.53: 1540-055: (S) "void*(ThreadClass::*)()" cannot be converted to "extern "C" void*(*)(void*)". rc = pthread_create(&thread, NULL, ThreadClass::run, NULL); #else // Instead, this is the correct way to start a thread on a C++ object rc = pthread_create(&thread, NULL, ThreadStartup, t); #endif if (rc) { printf("Failed to create a thread\n"); exit(EXIT_FAILURE); } printf("Waiting for thread to complete\n"); rc = pthread_join(thread, NULL); if (rc) { printf("Failed to join to the thread, rc=%d\n"); exit(EXIT_FAILURE); } printf("Testcase complete\n"); exit(EXIT_SUCCESS); } // This function is a helper function. It has normal C linkage, and is // as the base for newly created ThreadClass objects. It runs the // run method on the ThreadClass object passed to it (as a void *). // After the ThreadClass method completes normally (i.e returns), // we delete the object. void *ThreadStartup(void *_tgtObject) { ThreadClass *tgtObject = (ThreadClass *)_tgtObject; printf("Running thread object in a new thread\n"); void *threadResult = tgtObject->run(); printf("Deleting object\n"); delete tgtObject; return threadResult; } void *ThreadClass::run(void) { printf("Entered the thread for object %.8x %.8x %.8x %.8x\n", this); printf("Object identity: return NULL; } %d, %d: %s\n", data1, data2, str);
Output
Entered test QP0WTEST/ACPPOBJ Create a ThreadClass object Start a real thread to process the ThreadClass object Waiting for thread to complete Running thread object in a new thread Entered the thread for object 80000000 00000000 d017dad2 57001f60 Object identity: 42, 35: Testing C++ object/thread creation Deleting object Testcase complete
Example
The following example contains code that brings up the MCH3402 error. #define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h" void *threadfunc(void *parm) { int rc = 2; printf("Inside secondary thread, return address of local variable.\n"); return &rc; /* THIS IS AN ERROR! */ /* AT THIS POINT, THE STACK FOR THIS THREAD MAY BE DESTROYED */ } int main(int argc, char **argv) { pthread_t thread; int rc=1; void *status; printf("Enter Testcase - %s\n", argv[0]); printf("Create thread that returns status incorrectly\n"); rc = pthread_create(&thread, NULL, threadfunc, NULL); checkResults("pthread_create()\n", rc); printf("Join to thread\n"); rc = pthread_join(thread, &status); checkResults("pthread_join()\n", rc); printf("Checking results from thread. Expect MCH3402\n"); /* Monitor for the MCH3402 exception in this range */ #pragma exception_handler(TestOk, 0, 0, _C2_ALL, _CTLA_HANDLE_NO_MSG, "MCH3402") rc = *(int *)status; #pragma disable_handler TestFailed: printf("Did not get secondary thread results (exception) as expected!\n"); goto TestComplete; TestOk: /* Control goes here for an MCH3402 exception */ printf("Got an MCH3402 as expected\n"); TestComplete: printf("Main completed\n"); return rc; }
Output
Enter Testcase - QP0WTEST/TPJOIN7 Create thread that returns status incorrectly Join to thread Inside secondary thread, return address of local variable. Checking results from thread. Expect MCH3402 Got an MCH3402 as expected Main completed
Use the OS/400 QShell Interpreter Use the spawn() API. Use the SMJOB CL command. Use the CRTJOBD CL command to create a special job description, then create your job using a mechanism that will use the job description.