00001 #ifndef __GTHREAD_H
00002 #define __GTHREAD_H
00003
00005
00006 #include "GSemaphore.h"
00007
00008 enum GThreadState
00009 {
00010 LGITHREAD_INIT = 1,
00011 LGITHREAD_RUNNING = 2,
00012 LGITHREAD_ASLEEP = 3,
00013 LGITHREAD_EXITED = 4,
00014 LGITHREAD_ERROR = 5
00015 };
00016
00017 class LgiClass GThread
00018 {
00019 GThreadState State;
00020 int ReturnValue;
00021 OsThread hThread;
00022
00023 #if defined WIN32
00024 friend uint WINAPI ThreadEntryPoint(int i);
00025 uint ThreadId;
00026 #elif defined POSIX
00027 friend void *ThreadEntryPoint(void *i);
00028 #else
00029 friend int32 ThreadEntryPoint(void *i);
00030 #endif
00031
00032 protected:
00033 bool DeleteOnExit;
00034
00035 public:
00036 GThread();
00037 virtual ~GThread();
00038
00039
00040 OsThread Handle() { return hThread; }
00041 #ifdef WIN32
00042 uint GetId() { return ThreadId; }
00043 #endif
00044 GThreadState GetState() { return State; }
00045 virtual int ExitCode();
00046 virtual bool IsExited();
00047
00048
00049 virtual void Run();
00050 virtual void Terminate();
00051
00052
00053 virtual int Main();
00054
00055
00056 virtual void OnBeforeMain() {}
00057 virtual void OnAfterMain() {}
00058 };
00059
00061 class GThreadOwner;
00062 class GThreadTarget;
00063 class GThreadWorker;
00064
00065 class GThreadJob
00066 {
00067 friend class GThreadWorker;
00068 GThreadTarget *Owner;
00069
00070 public:
00071 GThreadJob(GThreadTarget *o) { Owner = o; }
00072 virtual ~GThreadJob() {}
00073 virtual void Do() {}
00074 };
00075
00076 class GThreadTarget : public GSemaphore
00077 {
00078 friend class GThreadWorker;
00079
00080 protected:
00081 GThreadWorker *Worker;
00082
00083 public:
00084 GThreadTarget()
00085 {
00086 Worker = 0;
00087 }
00088
00089 virtual ~GThreadTarget() {}
00090
00091 virtual void Detach()
00092 {
00093 if (Lock(_FL))
00094 {
00095 Worker = 0;
00096 Unlock();
00097 }
00098 }
00099
00100 virtual void OnDone(GThreadJob *j) {}
00101 };
00102
00103 class GThreadWorker : public GThread, public GSemaphore
00104 {
00105 GArray<GThreadTarget*> Owners;
00106 GArray<GThreadJob*> Jobs;
00107 bool Loop;
00108
00109 public:
00110 GThreadWorker(GThreadTarget *First) : GSemaphore("GThreadWorker")
00111 {
00112 Loop = false;
00113 if (First)
00114 Attach(First);
00115 }
00116
00117 virtual ~GThreadWorker()
00118 {
00119 Loop = false;
00120 while (!IsExited())
00121 LgiSleep(1);
00122 if (Lock(_FL))
00123 {
00124 for (int i=0; i<Owners.Length(); i++)
00125 Owners[i]->Detach();
00126 Unlock();
00127 }
00128 }
00129
00130 void Attach(GThreadTarget *o)
00131 {
00132 GSemaphore::Auto a(this, _FL);
00133 if (!Owners.HasItem(o))
00134 {
00135 LgiAssert(o->Worker == this);
00136 Owners.Add(o);
00137 if (Owners.Length() == 1)
00138 {
00139 Loop = true;
00140 Run();
00141 }
00142 }
00143 }
00144
00145 void Detach(GThreadTarget *o)
00146 {
00147 GSemaphore::Auto a(this, _FL);
00148 LgiAssert(Owners.HasItem(o));
00149 Owners.Delete(o);
00150 }
00151
00152 virtual void AddJob(GThreadJob *j)
00153 {
00154 if (Lock(_FL))
00155 {
00156 Jobs.Add(j);
00157
00158 if (!Owners.HasItem(j->Owner))
00159 Attach(j->Owner);
00160
00161 Unlock();
00162 }
00163 }
00164
00165 virtual void DoJob(GThreadJob *j)
00166 {
00167 j->Do();
00168 }
00169
00170 int Main()
00171 {
00172 while (Loop)
00173 {
00174 GThreadJob *j = 0;
00175 if (Lock(_FL))
00176 {
00177 if (Jobs.Length())
00178 {
00179 j = Jobs[0];
00180 Jobs.DeleteAt(0, true);
00181 }
00182 Unlock();
00183 }
00184 if (j)
00185 {
00186 DoJob(j);
00187 if (Lock(_FL))
00188 {
00189 if (Owners.IndexOf(j->Owner) < 0)
00190 {
00191
00192 DeleteObj(j);
00193 }
00194 Unlock();
00195 }
00196 if (j)
00197 {
00198
00199 j->Owner->OnDone(j);
00200 }
00201 }
00202 else LgiSleep(50);
00203 }
00204 return 0;
00205 }
00206 };
00207
00208 class GThreadOwner : public GThreadTarget
00209 {
00210 public:
00211 GThreadOwner()
00212 {
00213 }
00214
00215 virtual ~GThreadOwner()
00216 {
00217 if (Lock(_FL))
00218 {
00219 if (Worker)
00220 Worker->Detach(this);
00221 Unlock();
00222 }
00223 }
00224 };
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 #endif