Chinaunix首页 | 论坛 | 博客
  • 博客访问: 353310
  • 博文数量: 90
  • 博客积分: 2017
  • 博客等级: 大尉
  • 技术积分: 615
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-19 08:10
文章分类

全部博文(90)

文章存档

2012年(4)

2011年(74)

2010年(11)

2009年(1)

分类: C/C++

2011-04-25 21:15:44

PJLIB基础库的使用

C/C++之PJSIP 2010-04-14 18:25:26 阅读438 评论0   字号: 

1.使用前的初始化和使用后的清理

PJSIP库里面封装了很多线程内存池;而且很多对象都是基于内存池创建的,所以几乎所以的库都需要初始化或创建
下面是pjlib,pjlib-util,pjnath,pjsua-lib库的初始化和关闭

显示行号 复制代码  这是一段程序代码。
  1. pj_status_t status;
  2. status = pj_init(); //初始化pjlib库返回PJ_SUCCESS表示成功
  3. status = pjlib_util_init(); //初始化pjlib-util库
  4. status = pjnath_init(); //初始化pjnath库
  5. status = pjsua_create(); //初始化pjsua-lib库;(里面初始化了pjlib,pjlib-util,pjnath)
  6. pj_shutdown(); //pjlib停止
  7. pjsua_destroy(); //pjsua-lib库的清理
.src_container{background-color:#e7e5dc; width:99%; overflow:hidden; margin:12px 0 12px 0 !important; padding:0px 3px 3px 0px} .src_container .titlebar{ background-color:#d4dfff; border:1px solid #4f81bd; border-bottom:0; padding:3px 24px; margin:0; width:auto; line-height:120%; overflow:hidden; text-align:left; font-size:12px} .src_container .toolbar{ display:inline; font-weight:normal; font-size:100%; float:right; cursor:hand; color:#00f; text-align:left; overflow:hidden} .toolbar span.button{ display:inline; font-weight:normal; font-size:100%; cursor:hand; color:#00f; text-align:left; overflow:hidden; cursor:pointer;} .src_container div.clientarea{ background-color:white; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; height:auto; overflow:auto; text-align:left; font-size:12px; font-family: "courier new","consolas","fixedsys",courier,monospace,serif} .src_container ol.mainarea{ padding:0 0 0 52px; margin:0; background-color:#f7f7ff !important} .number_show{ padding-left:52px !important; list-style:decimal outside !important} .number_show li{ list-style:decimal outside !important; border-left:1px dotted #4f81bd} .number_hide{ padding-left:0px !important; list-style-type:none !important} .number_hide li{ list-style-type:none !important; border-left:0px} ol.mainarea li{ display:list-item !important; font-size:12px !important; margin:0 !important; line-height:18px !important; padding:0 0 0 0px !important; background-color:#f7f7ff !important; color:#4f81bd} ol.mainarea li pre{color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important} .linewrap ol.mainarea li pre{white-space:pre-wrap; white-space:-moz-pre-wrapwhite-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word} ol.mainarea li pre.alt{ background-color:#f7f7ff !important}

 

2.缓冲池和内存池(caching,pool)

pjsip的内存池的使用规则:
每个内存池都是基于内存池工厂创建的;pjsip有一个默认的内存池工厂pj_caching_pool;
我喜欢把它叫做缓冲池;将来清理内存池的时候,可以关闭内存池也可直接关闭缓冲池;
    pj_caching_pool cp;
    pj_caching_pool_init(&cp, NULL, 1024*1024 );       //缓冲池
    pj_caching_pool_destroy(&cp); //释放工厂

    pj_pool_t pool = pj_pool_create(&cp.factory, "name", 1024, 1024, NULL); //创建内存池
    pj_pool_release(&pool); //释放内存池到工厂中,直接释放工厂可省略这一步
    void* p = pj_pool_alloc(pool, size); //在内存中开辟一个空间
    注:适当的初始化大小;内存池只能增加不能减小
    由于pjlib很多内部对象都用内存池,所以在对象释放之前不能释放内存池。

使用缓冲池和内存池
  1. //系统初始化的时候调用
  2. void create()
  3. {
  4. //初始化pjlib库返回PJ_SUCCESS表示成功
  5. pj_status_t status = pj_init();
  6. pj_caching_pool_init(&this->m_caching, NULL, 0);
  7. this->m_pool = pj_pool_create(&this->m_caching.factory, "", 256, 256, NULL);
  8. //初始化mutex
  9. pj_mutex_create(this->m_pool, "", PJ_MUTEX_SIMPLE, &this->m_pool_mutex);
  10. //创建一个lock给定时器用
  11. pj_lock_create_simple_mutex(this->m_pool, "timer_lock", &this->timer_heap_lock);
  12. //在内存池上开辟一块空间
  13. char *pmem = (char*)pj_pool_alloc(this->m_pool, 1024);
  14. //创建一个定时器堆
  15. pj_timer_heap_create(this->m_pool, MAX_TIMER_COUTN, &this->timer_heap);
  16. //给定时器加锁; 将来自动删除该锁,无需手工删除
  17. pj_timer_heap_set_lock(this->timer_heap, this->timer_heap_lock, true);
  18. }
  19. //系统退出的时候调用
  20. void destroy()
  21. {
  22. //删除mutex
  23. pj_mutex_destroy(this->m_pool_mutex);
  24. //删除定时器的堆
  25. pj_timer_heap_destroy(this->timer_heap);
  26. //清理内存池,这一步也可以删略;让caching_pool来清理
  27. pj_pool_destroy_int(this->m_pool);
  28. //清理缓冲池;所有在缓冲池建立的内存池都会被清理掉
  29. pj_caching_pool_destroy(&this->m_caching);
  30. //pjlib停止
  31. pj_shutdown();
  32. }
.src_container{background-color:#e7e5dc; width:99%; overflow:hidden; margin:12px 0 12px 0 !important; padding:0px 3px 3px 0px} .src_container .titlebar{ background-color:#d4dfff; border:1px solid #4f81bd; border-bottom:0; padding:3px 24px; margin:0; width:auto; line-height:120%; overflow:hidden; text-align:left; font-size:12px} .src_container .toolbar{ display:inline; font-weight:normal; font-size:100%; float:right; cursor:hand; color:#00f; text-align:left; overflow:hidden} .toolbar span.button{ display:inline; font-weight:normal; font-size:100%; cursor:hand; color:#00f; text-align:left; overflow:hidden; cursor:pointer;} .src_container div.clientarea{ background-color:white; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; height:auto; overflow:auto; text-align:left; font-size:12px; font-family: "courier new","consolas","fixedsys",courier,monospace,serif} .src_container ol.mainarea{ padding:0 0 0 52px; margin:0; background-color:#f7f7ff !important} .number_show{ padding-left:52px !important; list-style:decimal outside !important} .number_show li{ list-style:decimal outside !important; border-left:1px dotted #4f81bd} .number_hide{ padding-left:0px !important; list-style-type:none !important} .number_hide li{ list-style-type:none !important; border-left:0px} ol.mainarea li{ display:list-item !important; font-size:12px !important; margin:0 !important; line-height:18px !important; padding:0 0 0 0px !important; background-color:#f7f7ff !important; color:#4f81bd} ol.mainarea li pre{color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important} .linewrap ol.mainarea li pre{white-space:pre-wrap; white-space:-moz-pre-wrapwhite-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word} ol.mainarea li pre.alt{ background-color:#f7f7ff !important}


 

3.线程的介绍,及其线程的封装和使用

1.外部函数或线程使用到pjsip的时候,必须注册线程

隐藏行号 复制代码  注册线程
  1. pj_thread_desc desc;
  2. pj_bzero(desc, sizeof(desc));
  3. pj_thread_t *thread_;
  4. if (pj_thread_register("", desc, &thread_) != PJ_SUCCESS)
  5. return 0; /* 失败*/
.src_container{background-color:#e7e5dc; width:99%; overflow:hidden; margin:12px 0 12px 0 !important; padding:0px 3px 3px 0px} .src_container .titlebar{ background-color:#d4dfff; border:1px solid #4f81bd; border-bottom:0; padding:3px 24px; margin:0; width:auto; line-height:120%; overflow:hidden; text-align:left; font-size:12px} .src_container .toolbar{ display:inline; font-weight:normal; font-size:100%; float:right; cursor:hand; color:#00f; text-align:left; overflow:hidden} .toolbar span.button{ display:inline; font-weight:normal; font-size:100%; cursor:hand; color:#00f; text-align:left; overflow:hidden; cursor:pointer;} .src_container div.clientarea{ background-color:white; border:1px solid #4f81bd; margin:0; width:auto !important; width:100%; height:auto; overflow:auto; text-align:left; font-size:12px; font-family: "courier new","consolas","fixedsys",courier,monospace,serif} .src_container ol.mainarea{ padding:0 0 0 52px; margin:0; background-color:#f7f7ff !important} .number_show{ padding-left:52px !important; list-style:decimal outside !important} .number_show li{ list-style:decimal outside !important; border-left:1px dotted #4f81bd} .number_hide{ padding-left:0px !important; list-style-type:none !important} .number_hide li{ list-style-type:none !important; border-left:0px} ol.mainarea li{ display:list-item !important; font-size:12px !important; margin:0 !important; line-height:18px !important; padding:0 0 0 0px !important; background-color:#f7f7ff !important; color:#4f81bd} ol.mainarea li pre{color:black; line-height:18px; padding:0 0 0 12px !important; margin:0em; background-color:#fff !important} .linewrap ol.mainarea li pre{white-space:pre-wrap; white-space:-moz-pre-wrapwhite-space:-pre-wrap; white-space:-o-pre-wrap; word-wrap:break-word} ol.mainarea li pre.alt{ background-color:#f7f7ff !important} function CopyCode(key){var codeElement=null;var trElements=document.all.tags("ol");var i;for(i=0;i


2.线程的创建和使用
pj_thread_create(pool*,"", function, *arg, stack_size, flag, **pj_thread_t)//创建一个线程
pj_thread_destroy(thread); //注销一个线程
pj_thread_resume(thread); //线程继续
pj_thread_sleep(1500);      //当前的线程暂停1500毫秒
pj_thread_join(thrad);       //等待线程结束
pj_thread_proc函数原型是int thread_func(void * argv);


3.对pjlib的thread的线程的封装

1: class CSipThread 2: { 3: //1.实现一个int ()(void*)的函数,且在结束的地方设置m_thread_t=NULL 4: pj_thread_t *m_thread_t; 5: protected: 6:  7: /* int (pj_thread_proc)(void*); 8: * 线程函数;子类需要使用static函数来实现 9: * 子类函数中在结束的时候:必须将m_thread_t = NULL; 10: */ 11: pj_thread_proc *m_thread_function; 12:  13: /* 这个是实现函数; 14: * 子类需要实现一个run()的函数;在run函数中调用run_父类的函数 15: */ 16: virtual void run_(pj_pool_t *pool, pj_thread_proc *function); 17: public: 18: CSipThread(); 19: virtual ~CSipThread(); 20: virtual bool thread_running(); 21:  22: //等待线程结束,自动释放资源,且会将m_thread_t=NULL 23: virtual void thread_join(); 24:  25: //在线程自己退出的时候,没有需要手工释放资源,和设置m_thread_t=NULL 26: virtual void thread_destroy(); 27: }; 28: CSipThread::CSipThread() 29: { 30: this->m_thread_t = NULL; 31: } 32: CSipThread::~CSipThread() 33: { 34:  35: } 36: void CSipThread::run_(pj_pool_t *pool, pj_thread_proc *function) 37: { 38: if ( this->thread_running()) 39: return; 40: pj_status_t status = pj_thread_create(pool, "", function, this, 41: PJ_THREAD_DEFAULT_STACK_SIZE, NULL, &this->m_thread_t); 42: if (status != PJ_SUCCESS) 43: { 44: CFunctions::write_log(LM_ERROR, "Can't create timer thread. [result=%d]..\n", status); 45: } 46: } 47: bool CSipThread::thread_running() 48: { 49: if (this->m_thread_t == NULL) 50: return false; 51: else 52: return true; 53: } 54:  55: void CSipThread::thread_join() 56: { 57: if (this->m_thread_t == NULL) 58: return; 59:  60: // 等待线程结束 61: pj_thread_join(this->m_thread_t); 62: } 63:  64: void CSipThread::thread_destroy() 65: { 66: pj_thread_destroy(this->m_thread_t); 67: this->m_thread_t = NULL; 68: }


4.使用封装起来的thread线程对象

1: /* 使用封装后的线程注意事项 2: * 1. 必须定义一个static的静态函数 3: * 2. 在静态函数结束的时候必须调用thread_destroy(); 4: */ 5: class CSendThread : public CSipThread 6: { 7: //线程函数;在函数退出的时候必须调用thread_destroy(); 8: static int thread_func(void * argv); 9: public: 10: CSendThread(void); 11: virtual ~CSendThread(void); 12:  13: //再次封装了run_函数 14: void run(); 15: } 16:  17: void CSendThread::run() 18: { 19: if ( this->thread_running()) 20: return; 21:  22: SIP_GUARD(CInterFace::instance()->m_pool_mutex, obj); 23:  24: //调用父类的run_函数进行创建函数,开始运行;注意如果线程已经存在,那么直接返回 25: //不会再创建一个线程 26: this->run_(CInterFace::instance()->m_pool, &CSendThread::thread_func); 27: } 28:  29: int CSendThread::thread_func(void * argv) 30: { 31: // 线程函数的参数默认是当前对象,等同于this指针 32: CSendThread *this_thread = (CSendThread*)argv; 33:  34: thread_end: 35: // 在线程结束的时候,一定要调用thread_destroy();来删除线程 36: this_thread->thread_destroy(); 37: return 0; 38: }



4.互斥和锁,及其封装(mutex)

pj_mutex_create(this->m_pool, "", PJ_MUTEX_SIMPLE, &this->m_pool_mutex); //创建一个锁指针
pj_mutex_destroy(this->m_pool_mutex); //删除锁指针
pj_mutex_lock(m_mutex);   //加锁
pj_mutex_unlock(m_mutex); //解锁

1: /* 封装了mutex的使用方法 2: * 在创建对象时加锁、删除对象时解锁 3: */ 4: class Sip_Lock 5: { 6: pj_mutex_t *m_mutex; 7: public: 8: Sip_Lock(pj_mutex_t *mutex) 9: { 10: this->m_mutex = mutex; 11: pj_mutex_lock(m_mutex); 12: } 13: virtual ~Sip_Lock() 14: { 15: pj_mutex_unlock(m_mutex); 16: this->m_mutex = NULL; 17: } 18: }; 19:  20: /* 封装了sip_lock的使用,直接使用宏定义进行互斥 */ 21: #define SIP_GUARD(MUTEX, OBJ) Sip_Lock OBJ(MUTEX);

 

5.定时器(heap,callback,thread)

//创建定时器堆,设置定时器堆pool大小
pj_timer_heap_create(this->m_pool, MAX_TIMER_COUTN, &this->timer_heap);
pj_timer_heap_set_max_timed_out_per_poll(this->timer_heap, 20);

//对定时器加锁是lcok类型
pj_timer_heap_set_lock(this->timer_heap, this->timer_heap_lock, true);

//启动定时器轮询的线程
this->run_(this->m_pool, &CInterFace::timer_thread_fun);

//设置一个定时器
pj_timer_heap_schedule(this->timer_heap, entry, delay);

//取消一个定时器
pj_timer_heap_cancel(this->timer_heap, entry);

//定时器的入口点定义
struct pj_timer_entry
{
    void *user_data; // 定时器的用户数据;C++通常用类对象;C通常用struct
    int id; // 绝对的ID号;用来区分当user_datacb都相同的情况
    pj_timer_heap_callback *cb; // 定时器中的回调函数
};

//定时器回调函数的原型
void timer_callback(pj_timer_heap_t *timer_heap,struct pj_timer_entry *entry);

 

一个定时器的使用例子:
1. 创建一个定时器、创建一个线程
2. 创建一个定时器入口entry
3. 创建一个定时器的回调函数,在回调函数中必须重新将entry加入堆中

1: //创建定时器堆,设置定时器堆pool大小; 加锁; 2: pj_timer_heap_create(this->m_pool, MAX_TIMER_COUTN, &this->timer_heap); 3: pj_timer_heap_set_max_timed_out_per_poll(this->timer_heap, 20); 4: pj_timer_heap_set_lock(this->timer_heap, this->timer_heap_lock, true); 5:  6: //启动定时器轮询的线程 7: this->run_(this->m_pool, &CInterFace::timer_thread_fun); 8:  9:  10: //定时器的线程函数 11: int CInterFace::timer_thread_fun(void* argv) 12: { 13: CInterFace *this_thread = (CInterFace*)argv; 14: int rc; 15: while ( !CInterFace::instance()->application_exit() ) 16: { 17: pj_thread_sleep(1); 18:  19: #if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0 20: /* On Symbian, we must use OS poll (Active Scheduler poll) since 21: * timer is implemented using Active Object. 22: */ 23: rc = 0; 24: while (pj_symbianos_poll(-1, 0)) 25: ++rc; 26: #else 27: PJ_USE_EXCEPTION; 28: PJ_TRY 29: { 30: rc = pj_timer_heap_poll(CInterFace::instance()->timer_heap, NULL); 31: } 32: PJ_CATCH_ANY 33: { 34:  35: } 36: PJ_END; 37: #endif 38: } 39:  40: // 定时器轮询的线程退出;必须手工删除pj_thread_t指针,因为它使用了内存池! 41: CFunctions::write_log(LM_DEBUG, "pj_timer_heap_pool, ending.\n"); 42: this_thread->thread_destroy(); 43: return 0; 44: } 45:  46:  47: //启动一个定时器:也就是将一个entry添加到堆上面 48: void CInterFace::start_timer(pj_timer_entry* entry, pj_time_val *delay) 49: { 50: if ( !this->thread_running()) 51: return; 52:  53: SIP_GUARD(this->timer_heap_mutex, obj); 54: pj_timer_heap_schedule(this->timer_heap, entry, delay); 55: } 56:  57: //取消一个定时器:从堆上删除一个entry 58: void CInterFace::stop_timer(pj_timer_entry* entry) 59: { 60: if ( !this->thread_running()) 61: return; 62:  63: SIP_GUARD(this->timer_heap_mutex, obj); 64: pj_timer_heap_cancel(this->timer_heap, entry); 65: } 66:  67: //启动上报速度和进度的定时器 68: bool CBaseFile::start_timer_speedProgress() 69: { 70: this->m_timer_speed_tval.msec = 0; 71: this->m_timer_speed_tval.sec = 1; 72: this->m_timer_speed.user_data = this; 73: this->m_timer_speed.cb = &CBaseFile::callback_speed; 74: SIP_GUARD(this->m_run_speed_mutex, obj); 75: this->m_run_speed = true; 76: CInterFace::instance()->start_timer(&this->m_timer_speed, &this->m_timer_speed_tval); 77: return true; 78: } 79:  80: //取消上报进度和速度的定时器 81: void CBaseFile::stop_timer_speedProgress() 82: { 83: SIP_GUARD(this->m_run_speed_mutex, obj); 84: this->m_run_speed = false; 85: CInterFace::instance()->stop_timer(&this->m_timer_speed); 86: } 87:  88: //上报进度和速度的回调函数 89: void CBaseFile::callback_speed(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) 90: { 91: // 上报速度和状态的的 92: if (entry->user_data != NULL) 93: { 94: CBaseFile *file = (CBaseFile*)entry->user_data; 95:  96: uint speed_ = 0; 97: uint progress_ = 0; 98: file->get_speed_progress(speed_, progress_); 99:  100: if ( file->m_ice_session->is_running()) 101: { 102: CInterFace::instance()->report_speed( 103: file->get_userid().c_str(), 104: file->get_fileName().c_str(), 105: file->get_guid(), 106: speed_, 107: progress_); 108: } 109:  110: // 由于定时select出来后,就从堆上删除了;所以需要一直触发的定时器, 111: // 就必须在回调函数中,重新想堆中添加entry! 112: SIP_GUARD(file->m_run_speed_mutex, obj); 113: if ( file->m_run_speed) 114: CInterFace::instance()->start_timer(entry, &file->m_timer_speed_tval); 115: } 116: }



6.pj_str_t字符串

 

7.socket的封装和使用
阅读(3285) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~