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终止线程。执行流程这里不再重复。