leancloud / realtime-SDK-dotNET

LeanCloud Instants Messaging SDK for Portable & Unity & .NET Core written by c#
Apache License 2.0
13 stars 9 forks source link

Unity 在Android P系统上会闪退 #176

Closed mimicryryu closed 5 years ago

mimicryryu commented 5 years ago

如果选.net 4.6会闪退,CreateClient的时候对task result得到的client的访问会导致invalid pthread_t xxxx passed to libc 奔溃 选.net3.5不会闪退,但是对client的访问会导致线程卡主

创建Client的代码

private void CreateClient(string rid, LuaFunction resultCallback = null) {
        try {
            this.KDLLog("CreateClientAsync");
            m_realtime.CreateClientAsync(rid, platformName, deviceUniqueIdentifier).ContinueWith(t => {
                bool isSuccess = !t.IsFaulted && !t.IsCanceled;
                if (isSuccess) {
                    this.KDLLog("CreateClient done");
                    m_client = t.Result;
                    this.KDLLog("m_client = t.Result " + m_client.ClientId);
                    var conf = m_client.CurrentConfiguration;
                    this.KDLLog("m_client.CurrentConfiguration");
                    conf.AutoRead = false; // AutoRead is not required
                    this.KDLLog("conf.AutoRead = false"); //<----到达不了
                    m_client.CurrentConfiguration = conf;
                    this.KDLLog("m_client.CurrentConfiguration = conf");
                    m_client.OnMessageReceived -= OnNewChatMessageReceived;
                    this.KDLLog("m_client.OnMessageReceived -= OnNewChatMessageReceived");
                    m_client.OnMessageReceived += OnNewChatMessageReceived;
                    this.KDLLog("m_client.OnMessageReceived += OnNewChatMessageReceived");
                } else {
                    this.KDLLogErrorFormat("CreateClient failed! IsCanceled:{0} IsFaulted:{1} Exception:{2}", t.IsCanceled, t.IsFaulted, t.Exception);
                }
                EnqueueMainThreadCallback(() => {
                    if (resultCallback != null) {
                        if (resultCallback.IsAlive) {
                            resultCallback.Call(isSuccess);
                            resultCallback.Dispose();
                        } else {
                            this.KDLLogError("resultCallback is not alive!");
                        }
                    }
                });
            });
        } catch (Exception e) {
            this.KDLLogError("CreateClient Error: " + e.ToString());
            if (null != resultCallback) {
                resultCallback.Call(false);
                resultCallback.Dispose();
            }
        }
    }
mimicryryu commented 5 years ago

targetSdkVersion 26 compileSdkVersion 28

onerain88 commented 5 years ago

在 ContinueWith() 中的代码是执行在子线程的,我猜测是你的 lua 代码执行在了子线程导致的那个报错。 两种解决方法:

  1. 使用 await/async,代码可以更简单,推荐
  2. 在 ContinueWith() 的第二个参数,传递「主线程调度」,TaskScheduler.FromCurrentSynchronizationContext()
mimicryryu commented 5 years ago

我的luafunction会通过一个EnqueueMainThreadCallback方法排队到主线程调用的,我想应该不是这个问题

mimicryryu commented 5 years ago
    void EnqueueMainThreadCallback(System.Action call) {
        bool enqueued = false;
        while (!enqueued) {
            if (Monitor.TryEnter(m_mainThreadCallbackQueueLock, 50)) {
                m_mainThreadCallbackQueue.Enqueue(call);
                enqueued = true;
                Monitor.Exit(m_mainThreadCallbackQueueLock);
            }
        }
    }

    void LateUpdate() {
        CallMainThreadCallbacks();
    }

    void CallMainThreadCallbacks() {
        if (Monitor.TryEnter(m_mainThreadCallbackQueueLock)) {
            while (m_mainThreadCallbackQueue.Count > 0) {
                m_mainThreadCallbackQueue.Dequeue()();
            }
            Monitor.Exit(m_mainThreadCallbackQueueLock);
        }
    }
mimicryryu commented 5 years ago

我这边华为的P20pro是9系统,倒是没有问题,一台MIX3(MIUI10.3 Android9)出现了上述问题。我再观察别的设备看看吧

onerain88 commented 5 years ago
    void EnqueueMainThreadCallback(System.Action call) {
        bool enqueued = false;
        while (!enqueued) {
            if (Monitor.TryEnter(m_mainThreadCallbackQueueLock, 50)) {
                m_mainThreadCallbackQueue.Enqueue(call);
                enqueued = true;
                Monitor.Exit(m_mainThreadCallbackQueueLock);
            }
        }
    }

    void LateUpdate() {
        CallMainThreadCallbacks();
    }

    void CallMainThreadCallbacks() {
        if (Monitor.TryEnter(m_mainThreadCallbackQueueLock)) {
            while (m_mainThreadCallbackQueue.Count > 0) {
                m_mainThreadCallbackQueue.Dequeue()();
            }
            Monitor.Exit(m_mainThreadCallbackQueueLock);
        }
    }

这样实现可能死锁吧,如果在回调中会产生要插入主线程队列的情况

onerain88 commented 5 years ago

如果使用 .net 4.x,建议使用文档中 await/async 的方式

mimicryryu commented 5 years ago

线程问题应该是我这边用的bugly插件的问题,在分线程上上报错误时导致闪退了(昨天leancloud服务器有问题

onerain88 commented 4 years ago

如果是新项目,可以了解一下新版 SDK,基于 .net Standard 2.0 开发的