cocos2dx 多线程

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.线程

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //创建线程  
  2. PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,  
  3.                             const pthread_attr_t * attr,  
  4.                             void *(*start) (void *),  
  5.                             void *arg);  
  6.   
  7. //退出线程  
  8. PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr);  
  9.   
  10. //取消执行线程  
  11. PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread);  
  12.   
  13. //删除线程  
  14. PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid);  
  15.   
  16. //加入线程  
  17. PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread,  
  18.                           void **value_ptr);  
  19.   
  20. //初始化线程属性  
  21. PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr);  
  22.   
  23. //清理线程属性  
  24. PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr);  

3.2.互斥对象

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //初始化mutex  
  2. PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex,  
  3.                                 const pthread_mutexattr_t * attr);  
  4.   
  5. //销毁mutex,要注意如果是new的指针,需要手动释放,pthread_mutex_destroy并不会帮你释放  
  6. PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex);  
  7.   
  8. //加锁  
  9. PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex);  
  10.   
  11. //尝试加锁  
  12. PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex);  
  13.   
  14. //解锁  
  15. PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex);  
要注意的是mutex变量必须要被声明为pthread_mutex_t类型,且在使用前必须要被初始化,初始化有2种方式:

(1)静态初始化

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;  
(2)动态初始化
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 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;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值