注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Mihooke's blog

IT之恋

 
 
 

日志

 
 

Jrtplib源码分析(3)---源码文件功能(上)  

2014-11-20 13:36:24|  分类: jrtplib |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

首先我们要了解RTP(实时传输协议),可参考Wikipedia上面的详细介绍,了解了解就可以了。它是目前解决流媒体实时传输最好的解决办法,可以使用单播或多播协议,并且是建立在UDP协议之上的。

#ifndef JMUTEX_H

 

#define JMUTEX_H

 

#if (defined(WIN32) || defined(_WIN32_WCE))

#ifndef _WIN32_WCE

#include <process.h>

#endif // _WIN32_WCE

#include <winsock2.h>//如果是WIN32平台,则使用WIN32平台上的库文件

#include <windows.h>

 

//#define JMUTEX_CRITICALSECTION

#else // using pthread

#include <pthread.h>//否则,使用UNIX自带的标准线程头文件

#endif // WIN32

//下面3个宏定义是错误消息

#define ERR_JMUTEX_ALREADYINIT -1

#define ERR_JMUTEX_NOTINIT -2

#define ERR_JMUTEX_CANTCREATEMUTEX -3

 

class JMutex

{

public:

JMutex();

~JMutex();

int Init();

int Lock();

int Unlock();

bool IsInitialized()  { return initialized; }

private:

#if (defined(WIN32) || defined(_WIN32_WCE))

#ifdef JMUTEX_CRITICALSECTION

CRITICAL_SECTION mutex;//临界区对象,在windows.h中

#else // Use standard mutex

HANDLE mutex;//windows的内核互斥对象

#endif // JMUTEX_CRITICALSECTION

#else // pthread mutex

pthread_mutex_t mutex;//标准UNIX互斥对象

#endif // WIN32

bool initialized;

}; 

 

#endif // JMUTEX_H

这是jmutex.h的头文件,由于作者的完美考虑,同时兼容UNIX-LIKE 系统和MS-Windows系统,所以头文件中出现较多的#ifdef预定义语句。

重点看JMutex类,包含完整的构造函数(初始化为false)和析构函数(删除临界区,关闭互斥对象),Init()函数是对互斥体的初始化;Lock()函数,加锁操作,我们把Init()的原型拉过来看看:

int JMutex::Lock()

{

if (!initialized)

return ERR_JMUTEX_NOTINIT;

#ifdef JMUTEX_CRITICALSECTION

EnterCriticalSection(&mutex);

#else

WaitForSingleObject(mutex,INFINITE);

#endif // JMUTEX_CRITICALSECTION

return 0;

}

唔!有两个不认识的线程操作的函数,首先看EnterCriticalSection(),这个函数是在多个线程操作相同数据时,为了防止数据错乱,引入的互斥变量,让每个线程都按顺序访问变量。在这里则是让mutex互斥体进入临界区;再看WaitForSingleObject()函数,用来检测mutex的状态,使得返回为互斥对象,由于互斥,所以每次只有一个线程执行。

理解了Lock(),那么UnLock()则比较简单了,

int JMutex::Unlock()

{

if (!initialized)

return ERR_JMUTEX_NOTINIT;

#ifdef JMUTEX_CRITICALSECTION

LeaveCriticalSection(&mutex);

#else

ReleaseMutex(mutex);

#endif // JMUTEX_CRITICALSECTION

return 0;

}

LeaveCriticalSection()是离开临界区,ReleaseMutex()是释放临界区。

最后还有一个IsInitialized()成员函数,根据字面意思,就是判断mutex是否已经初始化了。

 

接下来是jthread.h头文件,包含JThread类。

#ifndef JTHREAD_H

 

#define JTHREAD_H

 

#include "jmutex.h"

 

#define ERR_JTHREAD_CANTINITMUTEX -1

#define ERR_JTHREAD_CANTSTARTTHREAD -2

#define ERR_JTHREAD_THREADFUNCNOTSET -3

#define ERR_JTHREAD_NOTRUNNING -4

#define ERR_JTHREAD_ALREADYRUNNING -5

 

class JThread

{

public:

JThread();

virtual ~JThread();

int Start();

int Kill();

virtual void *Thread() = 0;

bool IsRunning();

void *GetReturnValue();

protected:

void ThreadStarted();

private:

 

#if (defined(WIN32) || defined(_WIN32_WCE))

#ifdef _WIN32_WCE

DWORD threadid;//WIN32下定义线程ID

static DWORD WINAPI TheThread(void *param);

#else

static UINT __stdcall TheThread(void *param);

UINT threadid;

#endif // _WIN32_WCE

HANDLE threadhandle;//线程内核句柄

#else // pthread type threads

static void *TheThread(void *param);

pthread_t threadid;//标准定义线程ID

#endif // WIN32

void *retval;

bool running;

JMutex runningmutex;

JMutex continuemutex,continuemutex2;//3个对象成员

bool mutexinit;//对象的状态

};

 

#endif // JTHREAD_H

JThread类比JMutex类稍稍复杂些,因为JThread类要创建3个对象,并对它们进程一些初始化的判断和操作,比如,start()判断互斥体是否进行了初始化,并且返回相对应的错误值,对runningmutex互斥体加锁解锁操作,对线程句柄赋值,continuemutexcontinuemutex2互斥体的加锁解锁操作。Kill()函数解锁操作,并中断、关闭线程句柄。GetReturnValue()函数取得runningmutex的返回值。

接下来是一个TheThread()函数,是线程入口函数,参数为一个void指针。

#ifndef _WIN32_WCE

UINT __stdcall JThread::TheThread(void *param)

#else

DWORD WINAPI JThread::TheThread(void *param)

#endif // _WIN32_WCE

{

JThread *jthread;

void *ret;

 

jthread = (JThread *)param;

jthread->continuemutex2.Lock();

jthread->runningmutex.Lock();

jthread->running = true;

jthread->runningmutex.Unlock();

jthread->continuemutex.Lock();

jthread->continuemutex.Unlock();

ret = jthread->Thread();

jthread->runningmutex.Lock();

jthread->running = false;

jthread->retval = ret;

CloseHandle(jthread->threadhandle);

jthread->runningmutex.Unlock();

return 0;

}

定义一个JTread对象,并完成一系列对runningmutexcontinuemutex的动作,并调用Thread()完成特定的任务,应该注意到Thread()是纯虚函数,还记得纯虚函数的作用吗?在基类中不能对虚函数给出有意义的实现,便把它的实现留在了改基类的派生类中。此时,Thread()并没有具体的操作内容,等到派生类使用到Thread()时,便会具体定义动作,所以我们确定在jrtplib工程中一定有JThread类的派生类使用。

Start()创建新线程后,continuemutex互斥体来保护它,为新线程上锁,在runningmutex互斥体的保护下置运行状态变量runningtrue,这时候continuemutex才解锁。接下来,新线程被调度,成员函数TheThread()负责之后的操作,continuemutex2互斥体立即上锁,在runningmutex的保护下置runningtrue,此时为了Thread()操作,runningmutex执行解锁,之后操作是continuemutex进行一次加锁解锁动作(其实中间过程为Start()取得running值是true后再进行解锁操作),这之后的操作就明显了,在runningmutex的保护下置runningfalse,这是为了关闭句柄,关闭之后,恢复runningmutex互斥体的初始状态。这里充分说明了互斥体同步的思想,好好体会下,continuemutex互斥体是线程的创建到调度的过程;continuemutex2互斥体是被调度到执行的过程。

 

最后,还有一个JthreadAutoLock类,这个很容易理解

#ifndef JMUTEXAUTOLOCK_H

 

#define JMUTEXAUTOLOCK_H

 

#include "jmutex.h"

 

class JMutexAutoLock

{

public:

JMutexAutoLock(JMutex &m) : mutex(m) { mutex.Lock(); }

~JMutexAutoLock() { mutex.Unlock(); }

private:

JMutex &mutex;

};

 

#endif // JMUTEXAUTOLOCK_H

就是对JMutex对象的自动管理,包括加锁解锁操作。对应的分别是构造成员函数和析构函数。

 

体能充电mutex(互斥锁)

我们引入互斥锁,是为了保证共享数据操作的完整性,每个线程对象都可对应于一个mutex,根据字面意思,就是保证在任一时刻只能有一个线程访问该对象。由于在这里我们用的是WIN32库来实现互斥锁,所以不需要单独去创建和销毁互斥锁,由库函数实现就行了。它的操作有加锁和解锁,不论是哪种状态,都不可能有2个不同的线程同时得到,必须要等待解锁。值得注意的是,如果线程在加锁后解锁前被取消了,那么锁将永远保持锁定状态。

  评论这张
 
阅读(276)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017