1 /*
2  * thread.cxx
3  *
4  * Sample program to test PWLib threads.
5  *
6  * Portable Windows Library
7  *
8  * Copyright (c) 2001,2002 Roger Hardiman
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Roger Hardiman
23  *
24  * $Revision: 20385 $
25  * $Author: rjongbloed $
26  * $Date: 2008-06-04 05:40:38 -0500 (Wed, 04 Jun 2008) $
27  */
28 
29 /*
30  * This sample program tests threads is PWLib. It creates two threads,
31  * one which display the number '1' and one which displays the number '2'.
32  * It also demonstrates starting a thread with Resume(), using
33  * Suspend() and Resume() to suspend a running thread and two different
34  * ways to make a thread terminate.
35  */
36 
37 #include <ptlib.h>
38 #include <ptlib/pprocess.h>
39 
40 /*
41  * Thread #1 displays the number 1 every 10ms.
42  * When it is created, Main() starts executing immediatly.
43  * The thread is terminated by calling Stop() which uses a PSyncPoint with a
44  * 10ms timeout.
45  */
46 class MyThread1 : public PThread
47 {
48   PCLASSINFO(MyThread1, PThread);
49   public:
MyThread1()50     MyThread1() : PThread(1000,NoAutoDeleteThread)
51     {
52       Resume(); // start running this thread when it is created.
53     }
54 
Main()55     void Main() {
56       while (!shutdown.Wait(10)) { // 10ms delay
57         printf("1 ");
58         fflush(stdout);
59 	Sleep(10);
60       }
61     }
62 
Stop()63     void Stop() {
64       // signal the shutdown PSyncPoint. On the next iteration, the thread's
65       // Main() function will exit cleanly.
66       shutdown.Signal();
67     }
68 
69     protected:
70       PSyncPoint shutdown;
71 };
72 
73 
74 /*
75  * Thread #2 displays the number 2 every 10 ms.
76  * This thread will not start automatically. We must call
77  * Resume() after creating the thread.
78  * The thread is terminated by calling Stop() which sets a local variable.
79  */
80 class MyThread2 : public PThread
81 {
82   PCLASSINFO(MyThread2, PThread);
83   public:
MyThread2()84     MyThread2() : PThread(1000,NoAutoDeleteThread) {
85       exitFlag = PFalse;
86     }
87 
Main()88     void Main() {
89       while (1) {
90         // Check if we need to exit
91         exitMutex.Wait();
92         if (exitFlag == PTrue) {
93           exitMutex.Signal();
94           break;
95         }
96         exitMutex.Signal();
97 
98         // Display the number 2, then sleep for a short time
99         printf("2 "); fflush(stdout);
100 	Sleep(10); // sleep 10ms
101       }
102     }
103 
Stop()104     void Stop() {
105       // set the exit flag. On the next iteration, the thread's
106       // Main() function will exit cleanly.
107       exitMutex.Wait();
108       exitFlag = PTrue;
109       exitMutex.Signal();
110     }
111 
112     protected:
113       PMutex exitMutex;
114       PBoolean exitFlag;
115 };
116 
117 
118 /*
119  * The main program class
120  */
121 class ThreadTest : public PProcess
122 {
123   PCLASSINFO(ThreadTest, PProcess)
124   public:
125     void Main();
126 };
127 
128 PCREATE_PROCESS(ThreadTest);
129 
130 // The main program
Main()131 void ThreadTest::Main()
132 {
133   cout << "Thread Test Program" << endl;
134   cout << "This program will display the following:" << endl;
135   cout << "             2 seconds of 1 1 1 1 1..." << endl;
136   cout << " followed by 2 seconds of 1 2 1 2 1 2 1 2 1 2..." << endl;
137   cout << " followed by 2 seconds of 2 2 2 2 2..." << endl;
138   cout << " followed by 2 seconds of 1 2 1 2 1 2 1 2 1 2..." << endl;
139   cout << endl;
140   cout << "It tests thread creation, suspend and resume functions." << endl;
141   cout << endl;
142 
143   // Create the threads
144   MyThread1 * mythread1;
145   MyThread2 * mythread2;
146 
147   mythread1 = new MyThread1();
148   mythread2 = new MyThread2();
149 
150 
151   // Thread 1 should now be running, as there is a Resume() function
152   // in the thread constructor.
153   // Thread 2 should be suspended.
154   // Sleep for three seconds. Only thread 1 will be running.
155   // Display will show "1 1 1 1 1 1 1..."
156   sleep(2);
157 
158 
159   // Start the second thread.
160   // Both threads should be running
161   // Sleep for 3 seconds, allowing the threads to run.
162   // Display will show "1 2 1 2 1 2 1 2 1 2..."
163   mythread2->Resume();
164   sleep(2);
165 
166 
167   // Suspend thread 1.
168   // Sleep for 3 seconds. Only thread 2 should be running.
169   // Display will show "2 2 2 2 2 2 2..."
170   mythread1->Suspend();
171   sleep(2);
172 
173 
174   // Resume thread 1.
175   // Sleep for 3 seconds. Both threads should be running.
176   // Display will show "1 2 1 2 1 2 1 2 1 2..."
177   mythread1->Resume();
178   sleep(2);
179 
180 
181   // Clean up
182   mythread1->Stop();
183   mythread1->WaitForTermination();
184   cout << "Thread 1 terminated" << endl;
185 
186   mythread2->Stop();
187   mythread2->WaitForTermination();
188   cout << "Thread 2 terminated" << endl;
189 
190   delete mythread1;
191   delete mythread2;
192 
193 }
194 
195