///////////////////////////////////////////////////////////////////// // thrdsWithProc.cpp - class supporting creation of threads // // ver 2.0 // // Language: Visual C++, ver 6.0, SP 5 // // Platform: Dell Dimension 8100, Win 2000 Pro, SP 2 // // Application: CSE691/791 - SWM&A Demonstration // // Author: Jim Fawcett, CST 2-187, Syracuse Univ // // (315) 443-3948, jfawcett@twcny.rr.com // // // ///////////////////////////////////////////////////////////////////// #include "thrdsWithProc.h" #include using namespace std; //----< Win32 thread is created here >------------------------------- void thread::start() { CloseHandle(th); // in case we restart the thread th = (HANDLE)_beginthreadex( NULL, // default security attributes 0, // default stack size threadProc, // thread processing function (void*)this, // pointer to this thread object 0, // create thread in running state &threadID // thread identifier assigned by OS ); _alive = true; } //----< destroy thread >--------------------------------------------- thread::~thread() { _alive = false; CloseHandle(th); } //----< thread proc wrapper for derived class's run function >------- unsigned int __stdcall thread::threadProc(void *pSelf) { ((thread*)pSelf)->_proc.run(); ((thread*)pSelf)->_alive = false; return 0; } //----< wait until thread terminates >------------------------------- void thread::wait() { WaitForSingleObject(th,INFINITE); } //----< set thread priority >---------------------------------------- void thread::setPriority(thread::priority pr) { switch(pr) { case thread::low : ::SetThreadPriority(th,THREAD_PRIORITY_LOWEST); break; case thread::normal : ::SetThreadPriority(th,THREAD_PRIORITY_NORMAL); break; case thread::high : ::SetThreadPriority(th,THREAD_PRIORITY_HIGHEST); break; default : ::SetThreadPriority(th,THREAD_PRIORITY_NORMAL); } } //----< is this thread still alive? >-------------------------------- // // thread becomes alive when start() is called and becomes // not alive when its run() function completes // bool thread::alive() { return _alive; } //----< test stub >-------------------------------------------------- #ifdef TEST_THRDSWITHPROC #include "lockingPtr.h" using namespace std; /////////////////////////////////////////////////////////////// // Note: You must create derived classes to define all your // application's processing that you want allocated // to the thread. Examples are given on the next page. // /////////////////////////////////////////////////////////////// // non-queued processing for first demonstration class appProc1 : public processing { public: void run() { safeOut out(cout); for(int i=0; i<10; i++) { out << locker << "\n thread #1: " << _str << unlocker; ::Sleep(20); // relinquish control } } void setString(const string &s) { _str = s; } private: string _str; }; /////////////////////////////////////////////////////////////// // non-queued processing for first demonstration class appProc2 : public processing { public: void run() { safeOut out(cout); for(int i=0; i<10; i++) { out << locker << "\n thread #2: " << _str << unlocker; ::Sleep(1); // relinquish control } } void setString(const string &s) { _str = s; } private: string _str; }; /////////////////////////////////////////////////////////////// // queued processing for second demonstration class Qproc : public procWithQ { public: void run() { safeOut out(cout); string temp; do { while(_queue.length() == 0) ::Sleep(50); temp = deQ(); out << locker << "\n child thread deQ'd: " << temp << unlocker; } while(temp != "quit"); } }; // void main() { cout << "\n Demonstrating thread with processing class " << "\n ============================================\n"; cout.flush(); safeOut out(cout); appProc1 proc1; proc1.setString("a short message"); thread t1(proc1); t1.start(); appProc2 proc2; proc2.setString("a somewhat longer, and rather boring, message"); thread t2(proc2); t2.start(); t1.wait(); t2.wait(); out << "\n\n"; cout << "\n Demonstrating thread using procWithQ " << "\n --------------------------------------\n"; // Create processing object, defined above, // then create and start thread. Qproc proc3; thread t3(proc3); t3.start(); for(int i=0; i<10; i++) { // make a message string string temp("message #"); temp += TtoStr(i+1).convert(); // Now enQ a message to be handled by the child thread. // Note that no synchronization is necessary. That's // handled by the interface enQ(...) and deQ() functions. proc3.enQ(temp); out << locker << "\n main thread enQ'd: " << temp << unlocker; // Sleep used to slow down main thread so enQs and deQs interleave. ::Sleep(5); } string temp("quit"); proc3.enQ(temp); out << locker << "\n main thread enQ'd: " << temp << unlocker; t3.wait(); cout << "\n\n"; // out << locker << "\n restarting the thread with queue " << "\n ----------------------------------\n" << unlocker; t3.start(); proc3.enQ("started again"); proc3.enQ("now quitting"); proc3.enQ("quit"); t3.wait(); cout << "\n\n"; } #endif