jthread庫分析二:JThread類

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終止線程。執行流程這裏不再重複。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章