/* Program that retrieves return data from thread and writes trace data This program demonstrates the following: Using a global shared variable Creating a thread Waiting for the thread to end and detaching it Writing trace points that can be displayed later Choose your browser's option to save to local disk to download this code example. Send the program to your AS/400 and compile it using the development facilities supplied there. This program was developed and tested on a V4R4 system. This small program that is furnished by IBM is a simple example to provide an illustration. This example has not been thoroughly tested under all conditions. IBM, therefore, cannot guarantee or imply reliability, serviceability, or function of this program. All programs contained herein are provided to you "AS IS". THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. */ /************************************************************************/ /* */ /* test case: thread_rtv.c */ /* */ /* objective: pthread_create() semantics demo/example */ /* */ /* scenario: main(): pthread_create() */ /* pthread_join() */ /* */ /* thread: pthread_exit() */ /* */ /* description: Call pthread_create with valid parameters */ /* and default attributes. Wait for the thread to */ /* terminate using pthread_join. */ /* */ /* Shows a simple example of retrieving return data */ /* from a thread, of a global shared variable, of */ /* Qp0zUprintf to put trace points to be displayed */ /* by DSPCPATRC TYPE(*KERNEL). */ /* */ /* The Qp0zUprintf output will be identical to the */ /* printf. */ /* */ /* internal routines: thread */ /* */ /* external routines: pthread_create */ /* pthread_join */ /* pthread_exit */ /* Qp0zUprintf */ /* */ /* usage notes: Create this program using */ /* CRTCMOD DEFINE('_MULTI_THREADED') and CRTPGM */ /* Call it with no parameters. */ /* use DSPCPATRC TYPE(*KERNEL) */ /* to display the Qp0zUprintf output if desired. */ /* NOTE: */ /* When using kernel threads on you must start a */ /* threaded program by using spawn(). You must set a */ /* special flag in the inheritance structure that causes */ /* spawn() to make the child process enabled for kernel */ /* threads. There is no support for running a threaded */ /* application in an interactive job. This means that a */ /* threaded application cannot use the terminal for user */ /* interaction. */ /************************************************************************/ #include #include #include #include #include #include #include /* for usleep() */ /* Declare a thread start routine of a compatible type */ static void *mythread(void *); /* use volatile for shared variables as you see fit. In a threaded */ /* environment some variables should always be written immediately to */ /* main storage when modified. */ static volatile int thread_created = 0; /* Declare the main function using the argc, argv format even if you */ /* don't intend to use them. */ int main (int argc, char **argv) { pthread_t thread_id; void *thr_status; int status; char threadarg[100]; /* All printf's in this test will have matching Qp0zUprintf */ /* statements. This will allow the use of DSPCPATRC TYPE(*KERNEL) */ /* to examine the output also. */ printf("main: Entering %s\n", argv[0]); Qp0zUprintf("main: Entering %s\n", argv[0]); strcpy(threadarg, "Thread Belongs to process: "); strcat(threadarg, argv[0]); /* Create the thread with an argument of the name of the program */ /* NOTE: Any data passed to the thread must exist throughout the */ /* thread's use of that data and should not be shared between */ /* threads in a non synchronized manner. */ status = pthread_create(&thread_id, (const pthread_attr_t *)NULL, mythread, (void *)threadarg); if (status != 0) { printf("main: pthread_create() failed\n"); Qp0zUprintf("main: pthread_create() failed\n"); } /* Now use pthread_join to synchronize with the threads termination */ /* this synchronization allows us to not have a mutex for the */ /* static int 'thread_created' declared globally to this process */ /* the main thread will not proceed until the secondary thread */ /* has completed */ printf("main: waiting for thread to end\n"); Qp0zUprintf("main: waiting for thread to end\n"); status = pthread_join(thread_id, &thr_status); if (status == -1) { printf("main: pthread_join() failed\n"); Qp0zUprintf("main: pthread_join() failed\n"); } /* Print out a failure message or the thread return data */ printf("main: Data Returned from the thread: %s\n", ((thr_status == NULL) ? "" : (char *)thr_status)); Qp0zUprintf("main: Data Returned from the thread: %s\n", ((thr_status == NULL) ? "" : (char *)thr_status)); /* We're done with the threads allocated storage, free it */ free(thr_status); /* Check the shared variable and use it as a judgement of success */ /* or failure */ if ( thread_created ) { printf("main: testcase successful\n"); Qp0zUprintf("main: testcase successful\n"); return(0); } printf("main: testcase failed\n"); Qp0zPrintf("main: testcase failed\n"); return(1); } void *mythread(void *arg) { char *return_data; char *threadarg; /* Note we cast the parameter of the thread start routine to the */ /* expected type. */ threadarg = (char *)arg; printf("inside thread: parameter received : %s\n", arg); /* Allocate a return data 'structure' dynamically. This storage must*/ /* not be deallocated when the scope of this thread ends. */ return_data = (char *)malloc(50); if (return_data == NULL) pthread_exit(NULL); strcpy(return_data, "*** This can be return data of any type ***"); printf("inside thread: return data : %s\n",return_data); /* Note that if two threads were running through this code at */ /* the same time, the following statement could cause a bug. The */ /* thread_created variable is not protected by a mutex. The only */ /* threads running in this process are the main thread and this */ /* function. These two threads are synchronized by the pthread_join */ /* call in the main routine. */ ++thread_created; /* Use sleep just so the main thread has something to wait for */ usleep(5); /* pthread_exit will not return to this thread but we put a return */ /* statement in to make the compiler happy */ pthread_exit((void *)return_data); return(NULL); }