JThread類的定義如下:
class JThread
{
public:
JThread();
virtual ~JThread();
int Start();
int Kill();
virtual void *Thread() = 0;
bool IsRunning();
void *GetReturnValue();
protected:
void ThreadStarted();
};
可以通過繼承JThread類創建自己的線程。Thread方法將會在新線程中執行,子類應該實現Thread方法。實現的Thread方法中必須立即調用ThreadStarted方法。
爲了啓動線程,需要調用Start方法。只有當你的Thread函數調用了ThreadStarted方法後,Start方法纔會返回。當Start方法返回後,你的Thread實現一定在運行。當然,你可以調用IsRunning函數檢查線程是否還在運行。如果線程已結束,那麼你可以調用GetReturnValue獲得返回值。
最後,如果你的線程有問題,你可以調用Kill函數終止線程執行。如果線程中使用了mutex,那麼kill之後,mutex可能處於locked狀態,這可能導致其它線程阻塞。
Linux下實現
JThread私有成員
class JThread
{
public:
JThread();
virtual ~JThread();
// ...
protected:
void ThreadStarted();
private:
//...
static void *TheThread(void *param);
pthread_t threadid;
void *retval;
bool running;
JMutex runningmutex;
JMutex continuemutex,continuemutex2;
bool mutexinit;
};
具體實現如下:
JThread::JThread()
{
retval = NULL;
mutexinit = false;
running = false;
}
JThread::~JThread()
{
Kill();
}
int JThread::Start()
{
int status;
//init runningmutex, continuemutex, continuemutex2
if (!mutexinit)
{
if (!runningmutex.IsInitialized())
{
if (runningmutex.Init() < 0)
return ERR_JTHREAD_CANTINITMUTEX;
}
if (!continuemutex.IsInitialized())
{
if (continuemutex.Init() < 0)
return ERR_JTHREAD_CANTINITMUTEX;
}
if (!continuemutex2.IsInitialized())
{
if (continuemutex2.Init() < 0)
return ERR_JTHREAD_CANTINITMUTEX;
}
mutexinit = true;
}
runningmutex.Lock();
if (running)
{
runningmutex.Unlock();
return ERR_JTHREAD_ALREADYRUNNING;
}
runningmutex.Unlock();
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//detached狀態的線程,在結束的時候,會自動釋放該線程所佔用的資源。
continuemutex.Lock();
status = pthread_create(&threadid,&attr,TheThread,this); //創建線程,在這裏 將會有兩個線程分支, main thread和執行用戶代碼的子線程t
pthread_attr_destroy(&attr);
if (status != 0)
{ // 線程創建失敗
continuemutex.Unlock();
return ERR_JTHREAD_CANTSTARTTHREAD;
}
/* Wait until 'running' is set */
runningmutex.Lock();
while (!running)
{
runningmutex.Unlock();
struct timespec req,rem;
req.tv_sec = 0;
req.tv_nsec = 1000000;
nanosleep(&req,&rem);
runningmutex.Lock();
}
runningmutex.Unlock();
/*Line-M1*/
continuemutex.Unlock();
/*Line-M2*/
continuemutex2.Lock(); // 主線程在此阻塞, 直到子線程調用了 ThreadStarted 方法
continuemutex2.Unlock();
/*Line-M3*/
return 0;
}
int JThread::Kill()
{
runningmutex.Lock();
if (!running)
{
runningmutex.Unlock();
return ERR_JTHREAD_NOTRUNNING;
}
pthread_cancel(threadid);
running = false;
runningmutex.Unlock();
return 0;
}
bool JThread::IsRunning()
{
bool r;
runningmutex.Lock();
r = running;
runningmutex.Unlock();
return r;
}
void *JThread::GetReturnValue()
{
void *val;
runningmutex.Lock();
if (running)
val = NULL;
else
val = retval;
runningmutex.Unlock();
return val;
}
void *JThread::TheThread(void *param)
{
JThread *jthread;
void *ret;
jthread = (JThread *)param;
jthread->continuemutex2.Lock();//continuemutex2加鎖, 在Thread方法中調用ThreadStarted後解鎖
jthread->runningmutex.Lock();
jthread->running = true; //線程開始運行,設置線程狀態true
jthread->runningmutex.Unlock();
/*Line-T1*/
jthread->continuemutex.Lock();
jthread->continuemutex.Unlock();
/*Line-T2*/
ret = jthread->Thread(); //調用 用戶實現的方法
jthread->runningmutex.Lock();
jthread->running = false; //線程結束運行,設置線程狀態false
jthread->retval = ret;
jthread->runningmutex.Unlock();
return NULL;
}
void JThread::ThreadStarted() // 參考TheThread方法
{
continuemutex2.Unlock();
/*Line-T3*/
}
假設主線程爲m, 子線程爲t。線程m在調用Start方法時,創建了子線程t。線程t執行TheThread方法, 而TheThread方法中調用了用戶實現的方法Thread。
線程m和t共有3次同步的過程:
- 第1次通過runningmutex同步線程的狀態running變量, 此時線程m執行到Line-M1,線程t執行到Line-T1;
- 第2次通過continuemutex再次同步線程, 此時線程m執行到Line-M2,線程t執行到Line-T2;
- 第3次通過continuemutex2同步線程, 此時線程m執行到Line-M3並返回,線程t執行到ThreadStarted方法中的Line-T3。顯然,若用戶不在Thread方法中調用ThreadStarted方法, 主線程m將阻塞,即使子線程結束也不會返回。
Windows下實現
windows下的實現與Linux下實現類似,不同的是創建線程,終止線程的方法不一樣。在Windows下采用_beginthreadex創建線程,TerminateThread終止線程。執行流程這裏不再重複。