4 * PWLib application source file for ThreadSafe
6 * Main program entry point.
8 * Copyright 2002 Equivalence
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
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.
34 #include <ptclib/random.h>
37 PCREATE_PROCESS(ThreadSafe
);
40 ///////////////////////////////////////////////////////////////////////////////
42 TestObject::TestObject(ThreadSafe
& proc
, unsigned 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
)
69 if (value
> othervalue
)
75 void TestObject::PrintOn(ostream
& strm
) const
81 ///////////////////////////////////////////////////////////////////////////////
83 ThreadSafe::ThreadSafe()
84 : PProcess("Equivalence", "ThreadSafe", 1, 0, AlphaCode
, 1)
92 ThreadSafe::~ThreadSafe()
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
114 void ThreadSafe::Main()
116 PArgList
& args
= GetArguments();
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'))
131 else if (args
.HasOption('2'))
133 else if (args
.HasOption('3'))
137 PTrace::ClearOptions(0);
142 void ThreadSafe::Test1(PArgList
& args
)
144 if (args
.GetCount() > 0)
145 threadCount
= args
[0].AsUnsigned();
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
;
156 PThread::Create(PCREATE_NOTIFIER(Test1Thread
), (INT
)duration
.GetMilliSeconds());
160 startTick
= PTimer::Tick();
161 while (threadCount
> 0) {
168 unsorted
.RemoveAll();
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()
190 cout
<< currentObjects
<< '/' << totalObjects
<< endl
;
191 mutexObjects
.Signal();
195 void ThreadSafe::Test1OutputEnd()
197 PSafePtr
<TestObject
> ptr
;
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
)
224 PSafePtr
<TestObject
> ptr
;
226 PTimer timeout
= duration
;
228 while (timeout
.IsRunning()) {
231 if (random
%(unsorted
.GetSize()+1) == 0)
232 unsorted
.Append(new TestObject(*this, random
));
236 if (random
%(sorted
.GetSize()+1) == 0)
237 sorted
.Append(new TestObject(*this, random
));
241 sparse
.SetAt(random
%20, new TestObject(*this, random
));
245 for (ptr
= unsorted
.GetWithLock(0, PSafeReference
); ptr
!= NULL
; ++ptr
) {
247 unsorted
.Remove(ptr
);
252 for (ptr
= sorted
.GetWithLock(0, PSafeReference
); ptr
!= NULL
; ++ptr
) {
259 sparse
.RemoveAt(random
%20);
263 for (ptr
= unsorted
; ptr
!= NULL
; ++ptr
)
268 for (ptr
= sorted
; ptr
!= NULL
; ++ptr
)
273 for (ptr
= sparse
; ptr
!= NULL
; ++ptr
)
278 for (ptr
= unsorted
.GetWithLock(0, PSafeReadOnly
); ptr
!= NULL
; ++ptr
)
283 for (ptr
= sorted
.GetWithLock(0, PSafeReadOnly
); ptr
!= NULL
; ++ptr
)
288 for (ptr
= sparse
.GetWithLock(0, PSafeReadOnly
); ptr
!= NULL
; ++ptr
)
293 for (ptr
= unsorted
.GetWithLock(0, PSafeReference
); ptr
!= NULL
; ++ptr
)
298 for (ptr
= sorted
.GetWithLock(0, PSafeReference
); ptr
!= NULL
; ++ptr
)
303 for (ptr
= sparse
.GetWithLock(0, PSafeReference
); ptr
!= NULL
; ++ptr
)
309 if ( unsorted
.GetSize() > 0 ) {
310 PSafePtr
<TestObject
> ptr2
= unsorted
.GetWithLock(unsorted
.GetSize() - 1, PSafeReadOnly
);
313 ptr2
= unsorted
.FindWithLock(*ptr2
, PSafeReadOnly
);
319 if ( sorted
.GetSize() > 0 ) {
320 PSafePtr
<TestObject
> ptr2
= unsorted
.GetWithLock(sorted
.GetSize() - 1, PSafeReference
);
323 ptr2
= sorted
.FindWithLock(*ptr2
, PSafeReference
);
335 void ThreadSafe::Test2(PArgList
&)
337 sparse
.SetAt(0, new TestObject(*this, 0));
340 PThread::Create(PCREATE_NOTIFIER(Test2Thread1
));
341 PThread::Create(PCREATE_NOTIFIER(Test2Thread2
));
343 while (threadCount
> 0)
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
;
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
;
365 void ThreadSafe::Test2Thread2(PThread
&, INT
)
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
;
377 void ThreadSafe::Test3(PArgList
&)
379 for (PINDEX i
= 0; i
< 10; i
++)
380 unsorted
.Append(new TestObject(*this, i
));
383 PThread::Create(PCREATE_NOTIFIER(Test3Thread1
));
384 PThread::Create(PCREATE_NOTIFIER(Test3Thread2
));
386 while (threadCount
> 0)
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
;
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
;
411 void ThreadSafe::Test3Thread2(PThread
&, INT
)
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
;
425 cout
<< "Thread 2 before read write unlock" << endl
;
426 ptr
->UnlockReadWrite();
427 cout
<< "Thread 2 after read write unlock" << endl
;
432 cout
<< "Thread 2 after enumeration, exiting" << endl
;
437 // End of File ///////////////////////////////////////////////////////////////