【Cocos2d-x Lua】异步任务工具类

本文介绍了如何在Cocos2d-x中使用Lua进行异步任务处理,包括实现思路、伪代码展示、实际代码实现、Lua绑定以及相关的线程间通信讨论。并提供了测试代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路


实现思路


1.使用pthread库,封装一个用于执行异步任务的类,该类提供一个方法接受一个lua function,然后在子线程中执行该function。
2.使用tolua++工具把C++自定义类绑定到Lua。

代码思路(伪代码)


定义一个C++类AsynTaskHandler用于处理Lua中需要执行的异步任务,这个类中有一个队列(先进先出)用于存放任务。
Task task = NULL;

//在子线程中启动一个循环去处理队列中的任务
while(true){

    //定义一个bool变量标记是否退出循环,在循环开始时判断是否需要退出循环
    if(need_quit){	
	break;
    }

    task = NULL;
    //从队列中获取任务
    task = task_queue.pop()
    
    //如果队列为空
    if(NULL == task){
        //当前线程进行睡眠状态,等待主线程添加任务并唤醒当前线程
	thread_sleep();
	//当线程被唤醒,继续当前循环
        continue;
    }
    
    //如果成功获取到任务则执行任务
    doTask(task);
    task.release();    
}

//如果退出了循环
//清理任务队列和资源
if(task_queue){
    task_queue.clear();
    task_queue = NULL;
}
//退出线程
thread_exit();
//初始化
void AsynTaskHandler::lazyInit()
{
    //如果任务队列未初始化
	if (taskQueue == NULL)
	{
		//创建任务队列
        taskQueue = queue.create();
        
		// 创建线程
		thread_create();
		// 执行线程
		thead_execute();
		
        // 初始化退出标记为flase
		need_quit = false;
	}	
}


// 添加任务
void AsynTaskHandler::addTask(int task)
{
    // 初始化
	lazyInit();

	// 添加到任务队列	
    task_queue.add(task);
	// 唤醒工作线程
	thread_wakeup();
}

实现


#include "AsynTaskHandler.h"
#include "CCLuaEngine.h"  
#include 
   
   
    
    
//#include 
    
    
     
     

// 单例
static AsynTaskHandler *s_pAsynTask = NULL; 
// 任务队列
static CCArray* s_taskQueue = NULL;
//static std::vector
     
     
      
       s_taskQueue;

// 线程锁
static pthread_mutex_t  s_taskQueueMutex;

// 条件变量
static pthread_mutex_t		s_SleepMutex;
static pthread_cond_t		s_SleepCondition;


//线程id
static pthread_t s_workThread;
// 任务循环标记
static bool need_quit = false;

// 工作线程
static void* workThread(void *data){
	CCInteger* task = NULL;
	while (true) 
	{
		// 如果接收到退出信号,退出循环
		if (need_quit)
		{
			break;
		}
		
		task = NULL;
		// 从任务队列中获取在队头的任务
		pthread_mutex_lock(&s_taskQueueMutex); 
		if (0 != s_taskQueue->count())
		{
			task = dynamic_cast
      
      
       
       (s_taskQueue->objectAtIndex(0));
			s_taskQueue->removeObjectAtIndex(0);  			
		}
		pthread_mutex_unlock(&s_taskQueueMutex);

		// 如果队列中没有任务
		if (NULL == task)
		{
			// 线程进行睡眠状态,等待主线程添加任务并唤醒当前线程
			pthread_cond_wait(&s_SleepCondition, &s_SleepMutex);
			continue;
		}

		//如果获取任务成功,执行任务
		CCLuaStack* pStack = CCLuaEngine::defaultEngine()->getLuaStack();
		//第一个参数是函数的整数句柄,第二个参数是函数参数个数
		pStack->executeFunctionByHandler(task->getValue(),0);
		pStack->clean();
		task->release();
	}

	// 如果接收到退出信号,清理任务队列和释放资源
	pthread_mutex_lock(&s_taskQueueMutex);
	s_taskQueue->removeAllObjects();
	pthread_mutex_unlock(&s_taskQueueMutex);

	if (s_taskQueue != NULL) {
		pthread_mutex_destroy(&s_taskQueueMutex);
		pthread_mutex_destroy(&s_SleepMutex);
		pthread_cond_destroy(&s_SleepCondition);

		s_taskQueue->release();
		s_taskQueue = NULL;
	}
	pthread_exit(NULL);
	return 0;
}

void AsynTaskHandler::lazyInit()
{
	if (s_taskQueue == NULL)
	{
		//创建任务队列
		s_taskQueue = new CCArray();
		s_taskQueue->init();

		// 初始化线程锁
		pthread_mutex_init(&s_taskQueueMutex, NULL);

		// 初始化条件变量
		pthread_mutex_init(&s_SleepMutex, NULL);
		pthread_cond_init(&s_SleepCondition, NULL);

		// 创建线程
		pthread_create(&s_workThread, NULL, workThread, NULL);
		// 执行线程
		pthread_detach(s_workThread);	

		need_quit = false;
	}	
}

AsynTaskHandler::AsynTaskHandler(){}
AsynTaskHandler::~AsynTaskHandler(){
	// 停止循环
	need_quit = true;

	//销毁任务队列
	if (s_taskQueue != NULL) {
		// 唤醒线程,清理资源
		pthread_cond_signal(&s_SleepCondition);
	}
	s_pAsynTask = NULL;
}

/** Return the shared instance **/
AsynTaskHandler *AsynTaskHandler::getInstance(){
	if (s_pAsynTask == NULL) {
		s_pAsynTask = new AsynTaskHandler();
	}
	return s_pAsynTask;
}
	

/** Relase the shared instance **/
void AsynTaskHandler::destroy(){
	s_pAsynTask->release();
}


// 添加任务
void AsynTaskHandler::addTask(int task)
{
	lazyInit();

	// 添加到任务队列	
	pthread_mutex_lock(&s_taskQueueMutex);
	s_taskQueue->addObject(CCInteger::create(task));
	pthread_mutex_unlock(&s_taskQueueMutex);

	// 唤醒工作线程
	pthread_cond_signal(&s_SleepCondition);
}
#ifndef __ASYNTASKHANDLER_H__
#define __ASYNTASKHANDLER_H__

#include "cocos2d.h"

USING_NS_CC;


// Lua中执行异步任务的工具类
class AsynTaskHandler: public CCObject
{
public:

	AsynTaskHandler();
	virtual ~AsynTaskHandler();

	void addTask(int task);	

	// 懒加载
	void lazyInit();

	/** Return the shared instance **/
	static AsynTaskHandler *getInstance();

	/** Relase the shared instance **/
	static void destroy();
};


#endif  // __ASYNTASKHANDLER_H__

      
      
     
     
    
    
   
   


绑定到Lua


点击查看【使用tolua++工具在Lua中使用C++自定义类】

绑定到Lua时需要使用的pkg文件,代码如下:

class AsynTaskHandler: public CCObject
{
	AsynTaskHandler();
	~AsynTaskHandler();
	void addTask(LUA_FUNCTION task);	
	static AsynTaskHandler *getInstance();
	static void destroy();
};


cocos code ide工程中使用的代码提示文件,放在源码目录下:
--------异步任务工具类
--------------------------------
-- @module AsynTaskHandler

--------------------------------
-- @function [parent=#AsynTaskHandler] addTask 
-- @param self
-- @param #int task

--------------------------------
-- @function [parent=#AsynTaskHandler] destory 
-- @param self

--------------------------------
-- @function [parent=#AsynTaskHandler] getInstance 
-- @param self
-- @return AsynTaskHandler#AsynTaskHandler ret (return value: AsynTaskHandler)

return nil

测试


测试代码如下(Lua代码):

    -- 测试异步执行任务
    AsynTaskHandler:getInstance():addTask(function()
        cclog("asyn task is running..")
        for i=1, 30 do
            cclog("child thread num=%s",i)   
        end
    end)
    for i=1, 30 do
        cclog("main thread num=%s",i)   
    end


日志输出如下:

日志中可以看出“main thread num=1”被先输出了,也就是说主线程并没有被阻塞。

注意:在子线程中不能调用Cocos2d-x相关api(比如CCTextureCache),这是由于Cocos2d-x的内存管理机制所限制的。

1.Don’t call any functions which invokes Ref::retain(), Ref::release() or Ref::autorelease(), because AutoreleasePool are not thread-safe. Please refer to Reference Count and AutoReleasePool in Cocos2d-x for more details. Cocos2d-x use AutoreleasePool every where in its framework, so my suggestion is that, don’t invoke any cocos2d-x API in a new thread except Data Structures.
AutoreleasePool不是线程安全的。

2.If you want to load resources in a new thread, you can use TextureCache::addImageAsync()
如果你想异步加载资源,可以使用TextureCache::addImageAsync()。

3.pthread_cond_wait() seems have a bug, it can not wait at the first time, but works properly in subsequence.
pthread_cond_wait()有一个bug。它在第一次调用的时候不正常,但后继的使用能正常工作。

关于线程间通信


在Cocos2d-x2.x中可以使用CCNotificationCenter进行线程间通信(注意:CCNotificationCenter并非线程安全的)。
在Cocos2d-x3.x中可以使用EventCustomeListener进行线程间通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值