source: nscp/trunk/include/thread.h @ e0705d4

Last change on this file since e0705d4 was e0705d4, checked in by Michael Medin <michael@…>, 8 years ago

Initial release

  • Property mode set to 100644
File size: 5.3 KB
Line 
1// Thread.h: interface for the Thread class.
2//
3//////////////////////////////////////////////////////////////////////
4
5#pragma once
6
7
8/**
9 * @ingroup NSClientCompat
10 * Simple unnamed mutex to handle thread exit wait (used by the Thread class below)
11 *
12 * @version 1.0
13 * first version
14 *
15 * @date 02-13-2005
16 *
17 * @author mickem
18 *
19 * @par license
20 * This code is absolutely free to use and modify. The code is provided "as is" with
21 * no expressed or implied warranty. The author accepts no liability if it causes
22 * any damage to your computer, causes your pet to fall ill, increases baldness
23 * or makes your car start emitting strange noises when you start it up.
24 * This code has no bugs, just undocumented features!
25 *
26 */
27class UnnamedMutex {
28private:
29        HANDLE hMutex_;
30public:
31        /**
32         * Default c-tor.
33         * Creates an unnamed mutex with a given owner status
34         * @param owner true if we want to become owner of the mutex
35         */
36        UnnamedMutex(bool owner = false) {
37                hMutex_ = ::CreateMutex(NULL, owner, NULL);
38        }
39        /**
40         * Default d-tor.
41         * Closes the mutex
42         */
43        virtual ~UnnamedMutex() {
44                CloseHandle(hMutex_);
45        }
46        /**
47         * Wait for the mutex or timeout in dwMilliseconds milliseconds.
48         * @param dwMilliseconds The timeout value
49         * @return status
50         */
51        DWORD wait(DWORD dwMilliseconds = 0L) {
52                return ::WaitForSingleObject(hMutex_, dwMilliseconds);
53        }
54        /**
55         * Release the mutex
56         * @return status
57         */
58        BOOL free() {
59                return ::ReleaseMutex(hMutex_);
60        }
61};
62
63/**
64 * @ingroup NSClientCompat
65 * Thread helper class.
66 * This class wraps another class inside it and makes that class run in the background as a working thread.
67 * Notice that no threading issues are handled so you are on your own when it comes to that.
68 * This simply wraps some API function inside a pretty interface.
69 *
70 * @version 1.0
71 * first version
72 *
73 * @date 02-13-2005
74 *
75 * @author mickem
76 *
77 * @par license
78 * This code is absolutely free to use and modify. The code is provided "as is" with
79 * no expressed or implied warranty. The author accepts no liability if it causes
80 * any damage to your computer, causes your pet to fall ill, increases baldness
81 * or makes your car start emitting strange noises when you start it up.
82 * This code has no bugs, just undocumented features!
83 *
84 * @todo Make this class (or another) handle multiple instances of the thread ?
85 */
86template <class T>
87class Thread {
88private:
89        HANDLE hThread_;                // Thread handle
90        DWORD dwThreadID_;              // Thread ID
91        UnnamedMutex endMutext; // mutex to wait for end of thread
92        T* pObject_;                    // Wrapped object
93
94        typedef struct thread_param {
95                Thread* core;
96                T *instance;
97                LPVOID lpParam;
98        } thread_param;
99
100public:
101        /**
102         * Default c-tor.
103         * Sets up default values
104         */
105        Thread() : endMutext(false), hThread_(NULL), dwThreadID_(0), pObject_(NULL) {}
106        /**
107         * Default d-tor.
108         * Does not really kill the thread only closes the handle to it.
109         *  @bug Should perhaps kill the thread, delete the object etc ?
110         */
111        virtual ~Thread() {
112                if (hThread_)
113                        CloseHandle(hThread_);
114        }
115
116private:
117        /**
118         * Static thread instance (this is the real thread procedure that wraps the internal objects)
119         * This function will wait for <b>nice</b> termination of the process so if that does not happen the thread canoot quit.
120         *
121         * @param lpParameter thread_param* with arguments for the thread construction
122         * @return exit status
123         */
124        static DWORD WINAPI threadProc(LPVOID lpParameter) {
125                thread_param* param = static_cast<thread_param*>(lpParameter);
126                T* instance = param->instance;
127                Thread *core = param->core;
128                LPVOID lpParam = param->lpParam;
129                delete param;
130                core->endMutext.wait();
131                DWORD ret = instance->threadProc(lpParam);
132                core->endMutext.free();
133                return 0;
134        }
135
136public:
137        /**
138         * Create a thread and possibly send a parameter to it.
139         * If a thread has already been create this function will throw an exception
140         * <b>NOTICE</b> The object returned is managed inside this object so it is not very safe to use it.
141         *
142         * @param lpParam An argument to the thread
143         * @return An instance of the thread object.
144         * @throws char
145         * @bug the object return thing is *unsafe* and should be changed (if the thread is terminated that pointer is invalidated without any signal).
146         */
147        T* createThread(LPVOID lpParam = NULL) {
148                if (pObject_)
149                        throw "Could not create thread";
150                pObject_ = new T;
151                thread_param* param = new thread_param;
152                param->instance = pObject_;
153                param->core = this;
154                param->lpParam = lpParam;
155                hThread_ = ::CreateThread(NULL,0,threadProc,reinterpret_cast<VOID*>(param),0,&dwThreadID_);
156                return pObject_;
157        }
158        /**
159         * Ask the thread to terminate (within 5 seconds) if not return false.
160         * @return true if the thread has terminated
161         */
162        bool exitThread() {
163                if (!pObject_)
164                        throw "Could not terminate thread, has not been started yet...";
165                pObject_->exitThread();
166                std::cout << "Waiting for socket to close..." << std::endl;
167                DWORD dwWaitResult = endMutext.wait(5000L);
168                switch (dwWaitResult) {
169                        // The thread got mutex ownership.
170                        case WAIT_OBJECT_0:
171                                // TODO: Potential race condition if multipåle threads try to terminate the thread...
172                                delete pObject_;
173                                pObject_ = NULL;
174                                endMutext.free();
175                                return true;
176                                // Cannot get mutex ownership due to time-out.
177                        case WAIT_TIMEOUT:
178                                return false;
179
180                                // Got ownership of the abandoned mutex object.
181                        case WAIT_ABANDONED:
182                                return false;
183                }
184                return false;
185        }
186};
187
Note: See TracBrowser for help on using the repository browser.