【问题标题】:Cocos2d-x Multithreading sceanrio crashes the gameCocos2d-x Multithreading sceanrio 导致游戏崩溃
【发布时间】:2021-07-28 22:05:12
【问题描述】:

我的场景很简单:我使用 cocos2d-x 制作了一个游戏,我想为多人用户下载图像(FB 和 Google play),并在下载完成后将它们显示为按钮的纹理。 在理想世界中,事情按预期工作。 当这些按钮在下载完成之前被删除时,事情会变得很棘手。 所以回调函数处于奇怪的状态,然后我得到信号 11(SIGSEGV),代码 1(SEGV_MAPERR) 应用程序崩溃 这就是我实现它的方式 我有一个名为 PlayerIcon 的布局类。 cpp看起来像这样

void PlayerIcon::setPlayer(string userName, string displayName, string avatarUrl){
    try {
        //some code here
        downloadAvatar(_userName, _avatarUrl);
        //some code here
    }
    catch(... ){
    }
}

void PlayerIcon::downloadAvatar(std::string _avatarFilePath,std::string url) {
    if(!isFileExist(_avatarFilePath)) {
        try {
            auto downloader = new Downloader();
            downloader->onFileTaskSuccess=CC_CALLBACK_1(PlayerIcon::on_download_success,this);
            downloader->onTaskError=[&](const network::DownloadTask& task,int errorCode,
                                                        int errorCodeInternal,
                                                        const std::string& errorStr){
                log("error while saving image");

            };
            downloader->createDownloadFileTask(url,_avatarFilePath,_avatarFilePath);
        }
        catch (exception e)
        {
            log("error while saving image: test");
        }
    } else {
        //set texture for button
    }
}

void PlayerIcon::on_download_success(const network::DownloadTask& task){
    _isDownloading = false;
    Director::getInstance()->getScheduler()-> performFunctionInCocosThread(CC_CALLBACK_0(PlayerIcon::reload_avatar,this));
}

void PlayerIcon::reload_avatar(){
    try {
        // setting texture in UI thread
    }
    catch (...) {
        log("error updating avatar");
    }
}

正如我所说,在下载完成之前删除 PlayerIcon 之前一切正常。 我不知道当下载任务的回调指向已删除(或标记为删除)的 un 对象的方法时会发生什么。 我查看了下载器实现,它没有提供任何取消机制 我不知道如何处理这个

另外,cocos2dx 游戏在谷歌控制台有 10% 的崩溃率是正常的吗? 非常感谢任何帮助

【问题讨论】:

    标签: multithreading download cocos2d-x


    【解决方案1】:

    你会在 PlayerIcon 的析构函数中删除 de Downloader 吗?

    Apple 实现中有一个销毁被析构函数触发。

    -(void)doDestroy
    {
    // cancel all download task
    NSEnumerator * enumeratorKey = [self.taskDict keyEnumerator];
    for (NSURLSessionDownloadTask *task in enumeratorKey)
    {
    ....
    
    
    DownloaderApple::~DownloaderApple()
    {
        DeclareDownloaderImplVar;
        [impl doDestroy];
        DLLOG("Destruct DownloaderApple %p", this);
    }
    

    【讨论】:

      【解决方案2】:

      在cocos2d-x的demo代码中:DownloaderTest.cpp他们使用:

      std::unique_ptr<network::Downloader> downloader;
      
      downloader.reset(new cocos2d::network::Downloader());
      

      代替:

      auto downloader = new Downloader();
      

      【讨论】:

        【解决方案3】:

        看起来您正在将此网络代码构建为场景树的一部分。如果您在异步网络软件在后台运行时调用replaceScene/popScene...(),这将导致回调消失(场景将从场景堆栈中删除)并且您将从这里得到一个SEGFAULT

        如果这是您编写的方式,那么您可能希望将网络代码提取到一个全局对象(单例)中,您可以在其中对请求进行排队,然后从互联网上抓取它们,并将结果保存在全局对象的输出队列(或它们的名称和位置),然后让场景代码通过查询全局对象并在此时加载头像精灵来检查是否已接收到头像。

        请注意,这可能是间歇性问题,取决于您的机器和网络的速度,因此它可能不会持续触发。

        另一种解决方案...

        或者您可以在PlayerIcon::~PlayerIcon()(析构函数)中将函数指针设置为nullptr

        downloader->setOnFileTaskSuccess(nullptr);
        downloader->setOnTaskProgress(nullptr);
        

        然后将不会尝试调用您的回调函数,并且将避免SEGFAULT(希望如此)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多