source: branches/libc-0.6/src/emx/testcase/ibm/mutex_lck.c@ 2447

Last change on this file since 2447 was 1979, checked in by bird, 21 years ago

http://www-1.ibm.com/servers/enable/site/porting/iseries/overview/examples/mutex.txt

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 KB
Line 
1/*
2Program that uses mutex locking and unlocking
3
4In this program, multiple threads attempt to lock and unlock a mutex using
5the pthread_mutex_lock() function multiple times. These attempts cause each
6thread to wait for the mutex to be unlocked. This example shows how a mutex
7can be used to allow the creation of a simple thread-safe resource that is
8scoped to a process. It also shows how too much serialization can decrease
9the throughput of a multithreaded process.
10
11Choose your browser's option to save to local disk to download this code example.
12Send the program to your AS/400 and compile it using the development facilities
13supplied there. This program was developed and tested on V4R4.
14
15This small program that is furnished by IBM is a simple example to provide an
16illustration. This example has not been thoroughly tested under all conditions.
17IBM, therefore, cannot guarantee or imply reliability, serviceability, or function
18of this program. All programs contained herein are provided to you "AS IS".
19THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ARE EXPRESSLY DISCLAIMED.
21
22 */
23/********************************************************************/
24/* */
25/* test case: mutex_lck.c */
26/* */
27/* objective: Show semantics of pthread_mutex_lock() and */
28/* pthread_mutex_unlock() */
29/* */
30/* scenario: Create pthread_mutex */
31/* Lock mutex */
32/* create a process scoped resource to serialize */
33/* access to with the mutex. */
34/* Create THREAD_COUNT lock threads */
35/* Wait for all lock threads to start. */
36/* Each lock thread trys to lock mutex (blocks)*/
37/* Unlock mutex - causes a thread to lock mutex */
38/* After aquireing mutex, lock thread uses */
39/* the process scoped resource. */
40/* Each lock thread delays and unlocks mutex */
41/* Each Lock thread repeats lock & unlock */
42/* for a DOIT_COUNT times & exits */
43/* Join to all threads */
44/* Show the non corrupted resource after multiple */
45/* thread access. */
46/* Destroy mutex */
47/* */
48/* description: This demo is a valid case to have multiple */
49/* threads attempt to lock and unlock a mutex via */
50/* pthread_mutex_lock() multiple times. */
51/* causes each to wait for the unlock of the */
52/* mutex. It shows how a mutex is used to allow */
53/* the creation of a simple thread safe process */
54/* scoped resource. */
55/* This demo also shows how too much serialization*/
56/* can decrease the throughput of a multithreaded */
57/* process */
58/* */
59/* internal routines: lock_thread() */
60/* */
61/* external routines: pthread_create() */
62/* pthread_join() */
63/* pthread_cancel() */
64/* pthread_detach() */
65/* pthread_mutex_init() */
66/* pthread_mutex_destroy() */
67/* pthread_mutex_lock() */
68/* pthread_mutex_unlock() */
69/* gettimeofday() */
70/* sleep() */
71/* */
72/* usage notes: Compile this program using */
73/* CRTCMOD DEFINE('_MULTI_THREADED') and CRTPGM */
74/* Call it with no parameters. */
75/* When using kernel threads on you must start a */
76/* threaded program by using spawn(). You must set a */
77/* special flag in the inheritance structure that */
78/* causes spawn() to make the child process enabled */
79/* for kernel threads. There is no support for */
80/* running a threaded application in an interactive */
81/* job. This means that a threaded application cannot */
82/* use the terminal for user interaction. */
83/* Call it with no parameters. Output goes only */
84/* to the screen. To have output go to the CPA trace */
85/* user space and allow viewing via */
86/* DSPCPATRC TYPE(*KERNEL) */
87/* uncomment the line '#define CPATRC_OUTPUT' below. */
88/* */
89/********************************************************************/
90
91#include <pthread.h>
92#include <errno.h>
93#include <qp0ztrc.h>
94#include <stdio.h>
95#include <string.h>
96#include <stdlib.h>
97#include <time.h>
98#include <math.h>
99#include <unistd.h> /* for usleep */
100
101/* Uncomment the following line to have all output go to the */
102/* CPA trace user space so it can be displayed with */
103/* DSPCPATRC TYPE(*KERNEL) */
104#define CPATRC_OUTPUT
105#ifdef CPATRC_OUPUT
106 #undef printf
107 #define printf Qp0zUprintf
108#endif
109
110/* Global constants */
111#define THREAD_COUNT 5
112#define DOIT_COUNT 5
113
114/* Prototype of child threads, using the prototype to match the */
115/* pthread_startroutine_t is easiest */
116static void *lock_thread(void *);
117
118/* Global variables for all threads to access */
119static pthread_mutex_t mymutex;
120/* some resource that all threads are using. Access is serialized */
121/* using the mutex */
122volatile static int resource;
123
124/* Any information can be passed to the thread start routine */
125typedef struct {
126 int tnum; /* Thread number */
127 char string[50]; /* Short description */
128} threadparmdata_t;
129
130/* The main routine creates a process scoped resource and mutex */
131/* protecting that resource from multiple threads accessing it. */
132/* it then creates THREAD_COUNT threads who will manipulate the */
133/* resource. */
134/* After all threads have completed, the resource will be displayed */
135/* no data corruption should result on the resource because of the */
136/* mutex to synchronize access to it */
137int main (int argc, char *argv[])
138{
139 int status, dstatus;
140 int i;
141 int *join_status;
142 pthread_t threads[THREAD_COUNT];
143 threadparmdata_t threadparms[THREAD_COUNT];
144 struct timeval current_time;
145
146
147 printf("main: Entering %s\n", argv[0]);
148
149 printf("main: Create a mutex\n");
150 status = pthread_mutex_init(&mymutex, NULL);
151 if (status == -1) {
152 printf("main: Create mutex failed = %d\n", errno);
153 }
154
155 gettimeofday(&current_time, NULL);
156 printf("main: Time before attempting to lock = %d\n",
157 current_time.tv_sec);
158 status = pthread_mutex_lock(&mymutex);
159 if ( status != 0)
160 {
161 printf("main: Lock mutex failed, errno = %d\n", errno);
162 /* Try to destroy mutex. NOTE: it may fail if another thread */
163 /* is holding the mutex. At this point, we don't care, _BUT_ */
164 /* If this mutex destroy fails and the CPA process is exited with*/
165 /* the mutex still existing, a Synchronization VLOG will most */
166 /* likely be cut indicating this. mutexes should be destroyed by*/
167 /* the application program and not allowed to simply go out of */
168 /* scope and be desctroyed by the system. The system treats this */
169 /* as an abnormal condition */
170 ( void )pthread_mutex_destroy(&mymutex);
171 return(1);
172 } /* endif */
173
174 printf("main: This thread is holding the mutex and can manipulate the\n"
175 "main: resource at will without concern for other threads\n"
176 "main: interacting in evil ways with the resource\n");
177 resource = 0;
178 printf("main: Create threads that will block on locking the mutex\n");
179 /* Loop to create all secondary threads */
180 for ( i = 0; i < THREAD_COUNT ; i++ )
181 {
182 gettimeofday(&current_time, NULL);
183 threadparms[i].tnum = i;
184 sprintf(threadparms[i].string, "Thread #%d,time=%d\n",
185 i, current_time.tv_sec);
186 status = pthread_create(&threads[i],
187 (const pthread_attr_t *)NULL,
188 lock_thread,
189 (void *)&threadparms[i]);
190 if ( status != 0 ) {
191 /* Create thread failed - break from loop and quit */
192 printf("main: Create thread # %d failed - terminate\n", i);
193 /* Try to destroy mutex. NOTE: it may fail if another thread */
194 /* is holding the mutex. At this point, we don't care, _BUT_ */
195 /* If this mutex destroy fails and the CPA process is exited with*/
196 /* the mutex still existing, a Synchronization VLOG will most */
197 /* likely be cut indicating this. mutexes should be destroyed by*/
198 /* the application program and not allowed to simply go out of */
199 /* scope and be desctroyed by the system. The system treats this */
200 /* as an abnormal condition */
201 ( void )pthread_mutex_destroy(&mymutex);
202 return(2);
203 } /* endif */
204 } /* endfor */
205
206 printf("main: sleep until all threads are blocked on mutex\n");
207 sleep(10);
208
209 gettimeofday(&current_time, NULL);
210 printf("main: Time before attempting to unlock = %d\n",
211 current_time.tv_sec);
212 status = pthread_mutex_unlock(&mymutex);
213 if ( status != 0 )
214 {
215 /* Mutex unlock failed - break from loop and quit */
216 printf("main: Unlock mutex failed - terminate\n");
217 /* Try to destroy mutex. NOTE: it may fail if another thread */
218 /* is holding the mutex. At this point, we don't care, _BUT_ */
219 /* If this mutex destroy fails and the CPA process is exited with */
220 /* the mutex still existing, a Synchronization VLOG will most */
221 /* likely be cut indicating this. mutexes should be destroyed by */
222 /* the application program and not allowed to simply go out of */
223 /* scope and be desctroyed by the system. The system treats this */
224 /* as an abnormal condition */
225 ( void )pthread_mutex_destroy(&mymutex);
226 printf("main: Testcase failed\n");
227 return(3);
228 } /* endif */
229
230 for ( i = 0; i < THREAD_COUNT; i++ )
231 {
232 printf("main: Join to child thread %d\n", i+1);
233 status = pthread_join(threads[i], NULL);
234 if ( status!= 0 )
235 {
236 printf("main: Join to Child thread %d failed, errno=%d\n"
237 "main: Testcase failed\n", errno);
238 return(-1);
239 } /* endif */
240 } /* endfor */
241
242 printf("main: After %d threads performing %d manipulations,\n"
243 "main: the resource is %d\n", THREAD_COUNT,
244 DOIT_COUNT, resource);
245 (void)pthread_mutex_destroy(&mymutex);
246
247 printf("main: Testcase successful\n");
248 return(0);
249
250} /* end */
251
252
253/********************************************************************/
254/* function: lock_thread */
255/* */
256/* description: Thread which locks and unlocks mutex. */
257/* before accessing the resource that the mutex */
258/* serializes access to. */
259/* */
260/********************************************************************/
261void *lock_thread(void *parm)
262{
263 int status; /* return status of APIs */
264 int i; /* loop variable */
265 struct timeval current_time; /* local time value */
266 int tnum = ((threadparmdata_t *)parm)->tnum;
267 /* Note: this parameter assignment doesn't copy the data, it */
268 /* still points to the data assigned up in the main thread and */
269 /* any modifications or deallocation of memory there, will have */
270 /* adverse affects here */
271 char *descript = ((threadparmdata_t *)parm)->string;
272
273
274 printf("lt #%d: %s\n", tnum, descript);
275
276 for ( i=0; i < DOIT_COUNT; ++i ) {
277 gettimeofday(&current_time, NULL);
278 printf("lt #%d: Current time in secs = %d\n",
279 tnum, current_time.tv_sec);
280
281 /* get the mutex to serialize access to the resource */
282 /* the threads should not access this resource until the mutex */
283 /* is locked */
284 printf("lt #%d: Lock the mutex\n", tnum);
285 status = pthread_mutex_lock(&mymutex);
286 if (status != 0) {
287 printf("lt #%d: Mutex lock failed = %d\n", tnum, errno);
288 pthread_exit(NULL);
289 }
290
291 /* Use the process scoped resource in a thread safe manner. */
292 /* this means that we only use it when holding its mutex */
293 gettimeofday(&current_time, NULL);
294 printf("lt #%d: this thread now holds the mutex to serialize access\n"
295 "lt #%d: to the resource, time = %d\n",
296 tnum, tnum, current_time.tv_sec);
297 /* pretend we're off processing while holding the mutex and */
298 /* this shows how the serialization on one mutex can slow down */
299 /* the processing of the entire job. Really, the mutex should */
300 /* be held only around the access/use of the resource */
301 usleep(1);
302 ++resource;
303 gettimeofday(&current_time, NULL);
304 printf("lt #%d: Current time before unlock= %d\n",
305 tnum, current_time.tv_sec);
306
307 /* unlock the mutex, allowing other threads to access the */
308 /* resource. */
309 status = pthread_mutex_unlock(&mymutex);
310 if (status != 0) {
311 printf("lt #%d: Mutex unlock failed = %d\n", tnum, errno);
312 pthread_exit(NULL);
313 }
314 } /* endfor */
315
316 return(NULL);
317} /* end */
318
Note: See TracBrowser for help on using the repository browser.