Added trace log at level 6 for helping find PSafeObject reference/dereference errors.
[pwlib.git] / samples / ThreadSafe / main.cxx
blobabd003256bf23a0e3f74227342a069f5adf4963b
1 /*
2 * main.cxx
4 * PWLib application source file for ThreadSafe
6 * Main program entry point.
8 * Copyright 2002 Equivalence
10 * $Log$
11 * Revision 1.6 2004/04/04 13:24:19 rjongbloed
12 * Changes to support native C++ Run Time Type Information
14 * Revision 1.5 2003/10/27 22:12:56 dereksmithies
15 * Add more good changes to get Compare method work. Thanks to Gene Small
17 * Revision 1.4 2003/10/13 23:38:31 dereksmithies
18 * Add debugging statements, usage(), Fixed Compare method. Thanks Gene Small.
20 * Revision 1.3 2002/12/11 03:38:45 robertj
21 * Added more tests
23 * Revision 1.2 2002/05/02 00:30:26 robertj
24 * Added dump of thread times during start up.
26 * Revision 1.1 2002/05/01 04:16:44 robertj
27 * Added thread safe collection classes.
31 #include <ptlib.h>
32 #include "main.h"
34 #include <ptclib/random.h>
37 PCREATE_PROCESS(ThreadSafe);
40 ///////////////////////////////////////////////////////////////////////////////
42 TestObject::TestObject(ThreadSafe & proc, unsigned val)
43 : process(proc)
45 value = val;
47 process.mutexObjects.Wait();
48 process.totalObjects++;
49 process.currentObjects++;
50 process.mutexObjects.Signal();
54 TestObject::~TestObject()
56 process.mutexObjects.Wait();
57 process.currentObjects--;
58 process.mutexObjects.Signal();
62 PObject::Comparison TestObject::Compare(const PObject & obj) const
64 PAssert(PIsDescendant(&obj, TestObject), PInvalidCast);
65 unsigned othervalue = ((const TestObject &)obj).value;
67 if (value < othervalue)
68 return LessThan;
69 if (value > othervalue)
70 return GreaterThan;
71 return EqualTo;
75 void TestObject::PrintOn(ostream & strm) const
77 strm << value;
81 ///////////////////////////////////////////////////////////////////////////////
83 ThreadSafe::ThreadSafe()
84 : PProcess("Equivalence", "ThreadSafe", 1, 0, AlphaCode, 1)
86 threadCount = 0;
87 totalObjects = 0;
88 currentObjects = 0;
92 ThreadSafe::~ThreadSafe()
94 unsorted.RemoveAll();
95 sorted.RemoveAll();
96 sparse.RemoveAll();
99 void ThreadSafe::Usage()
101 cout << "Usage: threadsafe {options} [number]" << endl
102 << "-t (more t's for more detail) logging on" << endl
103 << "-o output file for logging" << endl
104 << "-1 (or --test1) carry out test 1" << endl
105 << "-2 (or --test2) carry out test 2" << endl
106 << "-3 (or --test3) carry out test 3" << endl
107 << "The number field is optional, and specifies the number of threads for test 1" << endl
108 << endl;
109 return;
114 void ThreadSafe::Main()
116 PArgList & args = GetArguments();
118 args.Parse(
119 "t-trace." "-no-trace."
120 "o-output:" "-no-output."
121 "1-test1." "-no-test1."
122 "2-test2." "-no-test2."
123 "3-test3." "-no-test3.");
125 PTrace::Initialise(args.GetOptionCount('t'),
126 args.HasOption('o') ? (const char *)args.GetOptionString('o') : NULL,
127 PTrace::Blocks | PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine);
129 if (args.HasOption('1'))
130 Test1(args);
131 else if (args.HasOption('2'))
132 Test2(args);
133 else if (args.HasOption('3'))
134 Test3(args);
135 else Usage();
137 PTrace::ClearOptions(0);
138 PTrace::SetLevel(0);
142 void ThreadSafe::Test1(PArgList & args)
144 if (args.GetCount() > 0)
145 threadCount = args[0].AsUnsigned();
146 else
147 threadCount = 99;
149 cout << "Starting " << threadCount << " threads." << endl;
151 for (PINDEX i = 0; i < threadCount; i++) {
152 PTimeInterval duration = PRandom::Number()%540000 + 60000;
153 cout << setw(4) << (i + 1) << '=' << duration;
154 if (i%5 == 4)
155 cout << '\n';
156 PThread::Create(PCREATE_NOTIFIER(Test1Thread), (INT)duration.GetMilliSeconds());
158 cout << endl;
160 startTick = PTimer::Tick();
161 while (threadCount > 0) {
162 Test1Output();
163 Sleep(5000);
166 Test1OutputEnd();
167 sorted.RemoveAll();
168 unsorted.RemoveAll();
169 sparse.RemoveAll();
170 Test1OutputEnd();
174 void ThreadSafe::Test1Output()
176 PSafePtr<TestObject> ptr;
177 sorted.DeleteObjectsToBeRemoved();
178 unsorted.DeleteObjectsToBeRemoved();
179 sparse.DeleteObjectsToBeRemoved();
181 cout << setprecision(0) << setw(5) << (PTimer::Tick() - startTick)
182 << " Threads=" << threadCount
183 << ", Unsorted=" << unsorted.GetSize()
184 << ", Sorted=" << sorted.GetSize()
185 << ", Dictionary=" << sparse.GetSize()
186 << ", Objects:";
189 mutexObjects.Wait();
190 cout << currentObjects << '/' << totalObjects << endl;
191 mutexObjects.Signal();
195 void ThreadSafe::Test1OutputEnd()
197 PSafePtr<TestObject> ptr;
199 Test1Output();
201 cout << setprecision(0) << setw(5) << (PTimer::Tick() - startTick) << " Unsorted:" << endl;
202 for (ptr = unsorted.GetWithLock(0, PSafeReference); ptr != NULL; ++ptr) {
203 cout << *ptr << endl;
206 cout << setprecision(0) << setw(5) << (PTimer::Tick() - startTick) << " Sorted:" << endl;
207 for (ptr = sorted.GetWithLock(0, PSafeReference); ptr != NULL; ++ptr) {
208 cout << *ptr << endl;
211 cout << setprecision(0) << setw(5) << (PTimer::Tick() - startTick) << " Sparse:" << endl;
212 for (ptr = sparse.GetWithLock(0, PSafeReference); ptr != NULL; ++ptr) {
213 cout << *ptr << endl;
221 void ThreadSafe::Test1Thread(PThread &, INT duration)
223 PRandom random;
224 PSafePtr<TestObject> ptr;
226 PTimer timeout = duration;
228 while (timeout.IsRunning()) {
229 switch (random%17) {
230 case 0 :
231 if (random%(unsorted.GetSize()+1) == 0)
232 unsorted.Append(new TestObject(*this, random));
233 break;
235 case 1 :
236 if (random%(sorted.GetSize()+1) == 0)
237 sorted.Append(new TestObject(*this, random));
238 break;
240 case 2 :
241 sparse.SetAt(random%20, new TestObject(*this, random));
242 break;
244 case 3 :
245 for (ptr = unsorted.GetWithLock(0, PSafeReference); ptr != NULL; ++ptr) {
246 if (random%50 == 0)
247 unsorted.Remove(ptr);
249 break;
251 case 4 :
252 for (ptr = sorted.GetWithLock(0, PSafeReference); ptr != NULL; ++ptr) {
253 if (random%50 == 0)
254 sorted.Remove(ptr);
256 break;
258 case 5 :
259 sparse.RemoveAt(random%20);
260 break;
262 case 6 :
263 for (ptr = unsorted; ptr != NULL; ++ptr)
264 Sleep(random%50);
265 break;
267 case 7 :
268 for (ptr = sorted; ptr != NULL; ++ptr)
269 Sleep(random%50);
270 break;
272 case 8 :
273 for (ptr = sparse; ptr != NULL; ++ptr)
274 Sleep(random%50);
275 break;
277 case 9 :
278 for (ptr = unsorted.GetWithLock(0, PSafeReadOnly); ptr != NULL; ++ptr)
279 Sleep(random%50);
280 break;
282 case 10 :
283 for (ptr = sorted.GetWithLock(0, PSafeReadOnly); ptr != NULL; ++ptr)
284 Sleep(random%50);
285 break;
287 case 11 :
288 for (ptr = sparse.GetWithLock(0, PSafeReadOnly); ptr != NULL; ++ptr)
289 Sleep(random%50);
290 break;
292 case 12 :
293 for (ptr = unsorted.GetWithLock(0, PSafeReference); ptr != NULL; ++ptr)
294 Sleep(random%50);
295 break;
297 case 13 :
298 for (ptr = sorted.GetWithLock(0, PSafeReference); ptr != NULL; ++ptr)
299 Sleep(random%50);
300 break;
302 case 14 :
303 for (ptr = sparse.GetWithLock(0, PSafeReference); ptr != NULL; ++ptr)
304 Sleep(random%50);
305 break;
308 case 15 :
309 if ( unsorted.GetSize() > 0 ) {
310 PSafePtr<TestObject> ptr2 = unsorted.GetWithLock(unsorted.GetSize() - 1, PSafeReadOnly);
312 if ( ptr2 != NULL )
313 ptr2 = unsorted.FindWithLock(*ptr2, PSafeReadOnly);
316 break;
318 case 16 :
319 if ( sorted.GetSize() > 0 ) {
320 PSafePtr<TestObject> ptr2 = unsorted.GetWithLock(sorted.GetSize() - 1, PSafeReference);
322 if ( ptr2 != NULL )
323 ptr2 = sorted.FindWithLock(*ptr2, PSafeReference);
325 break;
328 Sleep(random%500);
331 threadCount--;
335 void ThreadSafe::Test2(PArgList &)
337 sparse.SetAt(0, new TestObject(*this, 0));
339 threadCount = 2;
340 PThread::Create(PCREATE_NOTIFIER(Test2Thread1));
341 PThread::Create(PCREATE_NOTIFIER(Test2Thread2));
343 while (threadCount > 0)
344 Sleep(1000);
348 void ThreadSafe::Test2Thread1(PThread &, INT)
350 cout << "Thread 1 before read only lock" << endl;
351 PSafePtr<TestObject> ptr = sparse.FindWithLock(0, PSafeReadOnly);
353 cout << "Thread 1 after read only lock, pausing ..." << endl;
354 Sleep(3000);
356 cout << "Thread 1 before read write lock" << endl;
357 ptr = sparse.FindWithLock(0, PSafeReadWrite);
359 cout << "Thread 1 after read write lock, exiting" << endl;
361 threadCount--;
365 void ThreadSafe::Test2Thread2(PThread &, INT)
367 Sleep(1000);
369 cout << "Thread 2 before read write lock" << endl;
370 PSafePtr<TestObject> ptr = sparse.FindWithLock(0, PSafeReadWrite);
372 cout << "Thread 2 after read write lock, exiting" << endl;
373 threadCount--;
377 void ThreadSafe::Test3(PArgList &)
379 for (PINDEX i = 0; i < 10; i++)
380 unsorted.Append(new TestObject(*this, i));
382 threadCount = 2;
383 PThread::Create(PCREATE_NOTIFIER(Test3Thread1));
384 PThread::Create(PCREATE_NOTIFIER(Test3Thread2));
386 while (threadCount > 0)
387 Sleep(1000);
391 void ThreadSafe::Test3Thread1(PThread &, INT)
394 cout << "Thread 1 before read only lock" << endl;
395 PSafePtr<TestObject> ptr = unsorted.GetWithLock(2, PSafeReadOnly);
397 cout << "Thread 1 after read only lock, pausing ..." << endl;
398 Sleep(2000);
400 cout << "Thread 1 before read write lock" << endl;
401 ptr.SetSafetyMode(PSafeReadWrite);
403 cout << "Thread 1 after read write lock, before ptr going out of scope" << endl;
405 cout << "Thread 1 after ptr out of scope, exiting" << endl;
407 threadCount--;
411 void ThreadSafe::Test3Thread2(PThread &, INT)
413 Sleep(1000);
415 cout << "Thread 2 before enumeration" << endl;
416 PSafePtr<TestObject> ptr = unsorted.GetWithLock(0, PSafeReadOnly);
417 while (ptr != NULL) {
418 if (ptr->value == 2) {
419 cout << "Thread 2 before read write lock" << endl;
420 ptr->LockReadWrite();
421 cout << "Thread 2 after read write lock" << endl;
423 Sleep(2000);
425 cout << "Thread 2 before read write unlock" << endl;
426 ptr->UnlockReadWrite();
427 cout << "Thread 2 after read write unlock" << endl;
429 ptr++;
432 cout << "Thread 2 after enumeration, exiting" << endl;
433 threadCount--;
437 // End of File ///////////////////////////////////////////////////////////////