How to multi-thread?

using multi-threaded loading bar to let me know how to use?

I perfer to use shcedule to implement this feature.
At first, in your init method

bool MyLayer::init()
{
    // your code before
    schedule( schedule_selector(MyLayer::loadingsStep), 1.0f); 
}

Then implement loadintStep callback

void MyLayer::loadingStep(ccTime dt)
{
    static int i = 0;
    switch (i)
   {
    case 0:
        // preload texture1
        // preload texture2
        // preload texture3
        // call CCProgressTimer::setPercentage(10.f) to step in the bar
        break;
   case 1:
        // preload texture4
        // preload texture5
        // preload texture6
        // call CCProgressTimer::setPercentage(20.f)
        break;

    // ...

    case 9:
        // preload sound1
        // preload sound2
        // call CCProgressTimer::setPercentage(100.f)
        break;
   }

   i++;
}
1 Like

thanks reply.
Incase the above examples.
when you load a large data, occured lag.

on the one side loading data
on the other side rendering layers without lag,

how do you have?

Another choice is to create thead by yourself. But this will invoke different APIs on different platforms.
e.g. on iOS, call NSThread.

I paste the code here

#import "interface.h"
#import "EAGLView.h"
#include "InfoLayer.h"

@implementation interface

+(BOOL)step1
{

    [NSThread detachNewThreadSelector:@selector(step2:)
                             toTarget:self
                           withObject:nil]; 

    return true;
}

+(void)step2:(NSNumber *)temp
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];

    EAGLContext *k_context = [[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup: [[[EAGLView sharedEGLView] context] sharegroup]] autorelease];
    [EAGLContext setCurrentContext:k_context];

    InfoLayer *pLayer = (InfoLayer *)CCDirector::sharedDirector()->getRunningScene()->getChildByTag(INFOLAYER_TAG);
    if (pLayer) {
        pLayer->ShowInfo();
    }

    [pool release];

}
@end

Be ware to call

    EAGLContext *k_context = [[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup: [[[EAGLView sharedEGLView] context] sharegroup]] autorelease];
    [EAGLContext setCurrentContext:k_context];

to make gl functions work correctly on ios. Ref to this topic on stackoverflow http://stackoverflow.com/questions/1133123/multi-threaded-opengl-programming-in-cocos2d-iphone

is it possible to use pthread in this case?

The answer to previous question is very interestring for me :slight_smile: Can you tell me anything about using pthread in cocos2d-x?
when I trying to update text field in CCLabelTTF it is dissapear from the screen.

Could I create new layer at another thread then add child into running scene

InfoLayer *pLayer = InfoLayer::create();
CCDirector::sharedDirector()->getRunningScene()->addChild(pLayer,0,INFOLAYER_TAG);

Here is an implementation for using multithread in cocos2dx with pthreads.
http://user.qzone.qq.com/19068906/blog/1376298015

it needs some changes in CCDirector.cpp.

After all is done, you can use it as following:

Implementing handler to process messages in UI trhead:

static bool processMessageInUIThread(const EXTCCMessage &msg) {
    switch(msg.msgId) {
    case MSG_UPDATING_LOADING_BAR: // a const value in int
        int progress = (int)msg.msgData;
        // updating loading bar
        break;

    case MSG_EXIT_WORK_THREAD_DONE:
        pWorkThread->unregisterHandler(processMessageInWorkThread);
        delete pWorkThread;
        pWorkThread = NULL;
        break;

    default:
        return false; // this is unknown message, leave it be processed by others
    }

    return true;
}

In the loading bar scene (it MUST be in UI thread), register the processMessage handler to main loop:

CCDirector::mainLoopHandler()->registerHandler(processMessageInUIThread);

In init of loading bar scene, creating worker thread to do real loading:

EXTCCHandlerThread *pWorkThread = EXTCCHandlerThread::create("LoadingThread");

Register the handler message in worker thread:

static bool processMessageInWorkThread(const EXTCCMessage &msg) {
    EXTCCMessage tmpMsg;

    switch(msg.msgId) {
    case MSG_REQUEST_TO_LOAD_DATA: {// a const value in int
        char *pDataPath = (char *)msg.msgData;
        int progress = 0;
        // do loading data
        tmpMsg.msgId = MSG_UPDATING_LOADING_BAR;
        while (progress <= 100) {
            // do loading
            progress += 10;
            tmpMsg.msgData = (void *)progress;
            CCDirector::mainLoopHandler()->postMessage(tmpMsg);
        }
        }
        break;

    case MSG_REQUEST_CANCEL_THREAD: // a const value in int
        tmpMsg.msgId = MSG_EXIT_WORK_THREAD_DONE;
        CCDirector::mainLoopHandler()->postMessage(tmpMsg);

        pthread_exit("");
        break;

    default:
        return false; // this is unknown message, leave it be processed by others
    }

    return true;
}

pWorkThread->registerHandler(processMessageInWorkThread);

Then request worker thread to do loading work

EXTCCMessage msg;
msg.msgId = MSG_REQUEST_TO_LOAD_DATA;
msg.msgData = (void *)"path_for_loading_data";
pWorkThread->postMessage(msg);

After the loading action is done, cancel the thread by sending MSG_REQUEST_CANCEL_THREAD:

EXTCCMessage msg;
msg.msgId = MSG_REQUEST_CANCEL_THREAD;
pWorkThread->postMessage(msg);
3 Likes

Thanks for your hard work.