http://blog.csdn.net/jackystudio/article/details/14118939
和其他框架一样,cocos2d-x允许我们使用多线程进行编程。cocos2d-x v2.2.0使用的是pthread库,是一套用户级线程库,被广泛地使用在跨平台应用上。
1.配置
在使用pthread之前,需要把头文件和库文件链接进来。pthread的官网戳这里,当然cocos2d-x帮我们包含进引擎了。
1.1.头文件
pthread.h放在\cocos2d-x目录\cocos2dx\platform\third_party\win32\pthread\下,右键项目→属性→配置属性→C/C++→附加包含目录添加如下,这里要注意附加包含目录是只包含当前目录下的文件,而不会包含该目录下子目录。
1.2.库文件
一样的,右键项目→属性→配置属性→链接器→输入→附加依赖项,添加pthreadVCE2.lib即可。v2.2.0会自动包含,这步可省。
2.pthread库
2.1.主要功能
pthread库包含了四大部分功能:
(1)Thread Management:线程管理。提供了线程的创建,删除,结束等功能,也包含了对线程属性的修改和设置。
(2)Mutexex:互斥对象。用于处理同步机制。提供了创建,销毁,加锁,解锁等功能,也包含了对互斥对象属性的修改和设置。
(3)Condition variables:条件变量。提供了基于程序员提供条件的进程间通讯互斥锁的操作,包含了对其属性的修改和设置。
(4)Synchronization:同步相关。提供了操作读写锁等功能。
2.2.命名规则
3.线程和互斥对象
我们这里主要了解线程和互斥对象,也是最常用到的。
3.1.线程
- //创建线程
- PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,
- const pthread_attr_t * attr,
- void *(*start) (void *),
- void *arg);
- //退出线程
- PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr);
- //取消执行线程
- PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread);
- //删除线程
- PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid);
- //加入线程
- PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread,
- void **value_ptr);
- //初始化线程属性
- PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr);
- //清理线程属性
- PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr);
3.2.互斥对象
- //初始化mutex
- PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex,
- const pthread_mutexattr_t * attr);
- //销毁mutex,要注意如果是new的指针,需要手动释放,pthread_mutex_destroy并不会帮你释放
- PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex);
- //加锁
- PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex);
- //尝试加锁
- PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex);
- //解锁
- PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex);
(1)静态初始化
- pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_init();
4.注意
cocos2d-x使用多线程应注意的问题(来自官方文档):
(1)不能调用涉及到CCObject::retain(), CCObject::release() 或者 CCObject::autorelease()的函数,因为CCAutoreleasePool不是线程安全的。因为cocos2d-x框架中无处不在使用CCAutoreleasePool,所以建议不要在新线程中调用cocos2d-x的API。
(2)如果要在新线程中加载资源,那么可以使用CCTextureCache::addImageAsync()。
(3)pthread_cond_wait()看起来有个bug,首次wait会失败,但是之后又会工作的很好。
(4)OpenGL context也不是线程安全。
示例
cpp
#include "threadTest.h"
int WebSocketTest::ticket=100;
pthread_mutex_t WebSocketTest::mutex;
CCScene* WebSocketTest::scene()
{
CCScene * scene=CCScene::create();
scene->addChild(WebSocketTest::create());
return scene;
}
bool WebSocketTest::init()
{
if(!CCLayer::init()){return false;}
pthread_mutex_init(&mutex,NULL);
//scoketTest();
//CreateThread();
//ticket=100;
pthread_create(&sellA_pid, NULL, &functionA, NULL);
pthread_create(&sellB_pid, NULL, &functionB, NULL);
return true;
}
void WebSocketTest::onEnterTransitionDidFinish()
{
}
void* WebSocketTest::functionA(void* arg)
{
SimpleStructure* args = (SimpleStructure*)arg;
// do something with args->data and args->otherData
while(true){
if(ticket>0){
pthread_mutex_lock(&mutex);
ticket--;
CCLOG("A ticket:%d",ticket);
pthread_mutex_unlock(&mutex);
Sleep(100);
}
else{
break;
}
}
delete args;
return NULL;
}
void* WebSocketTest::functionB(void* arg)
{
SimpleStructure* args = (SimpleStructure*)arg;
// do something with args->data and args->otherData
while(true){
if(ticket>0){
pthread_mutex_lock(&mutex);
ticket--;
CCLOG("B ticket:%d",ticket);
pthread_mutex_unlock(&mutex);
Sleep(100);
}
else{
break;
}
}
delete args;
return NULL;
}
void WebSocketTest::CreateThread()
{
/*pthread_create(&threadA, NULL, &functionA, 0);
pthread_create(&threadB, NULL, &functionB, 0);*/
}
WebSocketTest::~WebSocketTest()
{
pthread_mutex_destroy(&mutex);
}
.h
#pragma once;
#include "cocos2d.h"
#include "pthread.h"
USING_NS_CC;
struct SimpleStructure
{
int data;
float otherData;
};
class WebSocketTest:public CCLayer{
public:
static CCScene* scene();
bool init();
CREATE_FUNC(WebSocketTest);
void onEnterTransitionDidFinish();
static pthread_mutex_t mutex;
SimpleStructure *args;
void CreateThread();
static void* functionA(void* arg);
static void* functionB(void* arg);
static int ticket;
pthread_t sellA_pid,sellB_pid; //为什么不能为static
~WebSocketTest();
};
http://mrjake.blog.163.com/blog/static/10510910620124272139947/
线程终止thread_exit,pthread_cancel,pthread_join
/**
* @file demo1.c
* @Synopsis 线程终止
*
* 1: 线程使用return (这种方法对线程还适用,从main函数return 相当于调用exit)
* 2: 调用pthread_cancel (一个线程可以调用pthread_cancel终止同一进程中的另一个线程)
* 3: 调用pthread_exit(线程可以调用pthread_exit终止自己,有两种情况需要注意:
* 一种情况是,在主线程中,如果从main函数返回或是调用了exit函数退出主线程,
* 则整个进程将终止,此时进程中有线程也将终止,因此在主线程中不能过早地从main
* 函数返回;
* 另外一种情况:如果主线程调用pthread_exit函数,则仅仅是主线程消亡,
* 进程不会结束,进程内的其他线程也不会终止,直到所有线程结束,进程才会结束;
* 线程终止最重要的问题是资源释放问题,特别是一些临界资源在一段时间内只能被
* 一个线程所持有,当线程要使用临界资源需提出请求,如果该资源未被使用则申请
* 成功,否则等待。临界资源使用完毕后要释放以便其它线程可以使用。
* 例如:某线程要写一个文件,在写文件时一般不允许其他线程也对该文件执行写操作的,
* 否则会导致文件数据混乱。这里的文件就是一种临界资源。临界资源为一个线程所独占,
* 当一个线程终止时,如果不释放其占有临界资源。则该资源会被认为还己经退出的线程所
* 独占,当一个线程终止时,如果不释放其占有的临界资源,则该资源会被认为还被认为还被
* 己经退出的线程所使用,因而永远不会得到释放。如果一个线程在等待使用这个临界资源
* 它就可能无限的等待下去,这就形成了死锁,而这往往是灾难性的。
* 为此提供了一对函数:
* pthread_cleanup_push(),pthread_cleanup_pop()用于自动释放资源。
* 从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的
* 终止动作(如调用pthread_exit)都将执行pthread_cleanup_push()所指定的清理函数。
*
* #include <pthread.h>
* #define pthread_cleanup_push(routine,arg)\
* {\
* struct _pthread_clean_buffer buffer;\
* _pthread_cleanup_push(&buffer,(routine),srg);
* #define pthread_cleanup_pop _pthread_cleanup_pop(&buffer,(exeute));}
* }
* 线程终止时另外一个要注意的问题是线程间的同步问题。一般情况下,进程中各个线程
* 的运行是相互独立的,线程的终止并不会相互通知,也不会影响其他线程,
* 终止的所点用的资源不会随着线程的终止而归还糸统,而是仍为线程所在的进程持有。
* 正如进程之间可以使用wait()糸统调用来等待其他进程结束一样,线程也有类似的函数
* pthread_join()函数
* #include <pthread.h>
* void pthread_exit(void *retval);
* int pthread_join(pthread_t th,void *thread_return);
* int pthread_detach(pthread_t th);
*
* 函数pthread_join用来等待一个线程的结束。
* @param pthread_t th 调用者将被挂起并等待th线程终止;
* @param void *thread_return 如果不为NULL 则*thread_return=retval.
* 需要注意的是一个线程仅允许一个纯种使用pthread_join()等待它的终止,
* 并且被等待的线程应该处于可join状态,即非DETACHED状态。
* DETACHED 状态是指对某个线程执行pthread_detach()后其所处的状态。
* 处于DETACHED判词的线程无法由pthread_join()同步。
* 一个join的线程所占用的内存公当有线程对其执行了pthread_join()后才会释放,因此为了
* 避免内存泄漏,所有线程的终止时,要么己被设为DETACHED,要么使用pthread_join()
* 来回收资源。(注意:一个线程不能被多个线程等待,否则第一个接收到信号的线程成功
* 返回,其余调用pthread_join()的线程返回错误代码ESRCH)
* @author MrClimb
* @version 1.1.0
* @date 2012-05-27
*/
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
/* *************************************************************** */
/**
* @Synopsis 主线程通过pthread_join等待辅助线程结束
* int pthread_create(pthread_t *thread,const pthread_attr_t *attr,
* void *(*start_toutine)(void *),void *arg);
* int pthread_join(pthread_t thread,void **retval);
*
* Compile and link with -pthread
* gcc demo1.c -g -Wall -lpthread
*/
/* *************************************************************** */
void * pthread_join_test(void *arg)
{
printf("我是线程,我来帮你分担一些事情!\n");
sleep(3);
pthread_exit(0);
return NULL;
}
void test1()
{
pthread_t pid;
int statuscode;
pthread_create(&pid,NULL,pthread_join_test,NULL);
pthread_join(pid,(void *)&statuscode);
printf("我退出进的状态码是: %d\n",statuscode);
}
/* *************************************************************** */
/**
* @Synopsis 终止同一进程的另一线程
* int pthread_cancel(pthread_t thread);
* int pthread_create(pthread_t *thread,const pthread_attr_t *attr,
* void *(*start_toutine)(void *),void *arg);
* int pthread_join(pthread_t thread,void **retval);
*
*/
/* *************************************************************** */
void * pthread_cancel_test(void *arg)
{
while(1){
printf("我正在工作中!\n");
sleep(1);
}
}
void test2()
{
pthread_t pid;
// int status=0;
void *status;
pthread_create(&pid,NULL,pthread_cancel_test,NULL);
sleep(3);
pthread_cancel(pid);
pthread_join(pid,&status);
// pthread_join(pid,NULL);
printf("终止进程状态码:%d\n",(int)status);
}
int main(int argc, char **argv)
{
#if 0
test1();
/**
* 结果分析:
* 从运行结果可以看出pthread_join会阻塞主线程,等待pthread_join_test结束。
* pthread_exit结束的退出码是0,pthread_join得出status 也为0,两者是一致的。
*/
#endif
#if 1
test2();
#endif
return 0;
}