c++ - CEF base::ThreadRestrictions::AssertIOAllowed() 断言在应用程序退出时失败

标签 c++ macos chromium-embedded

我有一个简单的 OSX CEF 应用程序,它基于提供的 cefsample 应用程序。一个显着的变化是我在单进程模式下运行 (settings.single_process = true)。由于断言失败,我在退出时遇到崩溃。奇怪的是,这种崩溃也发生在发布版本中,而不仅仅是调试版本。

任何人(CEF 大师)都可以帮我理解这里的问题是什么吗?堆栈跟踪表明我正在从不允许 IO 的线程中调用“仅 IO”函数。我正在做的唯一 IO 是从应用程序包中加载静态 html 文件。这似乎不需要特殊处理。但是,好吧,让我们假设它确实需要我按照断言错误中的建议“在该线程的启动中调整对 base::ThreadRestrictions::SetIOAllowed() 的调用”——我不知道如何或在何处执行此操作。

这是堆栈跟踪:

[1120/110258:FATAL:thread_restrictions.cc(38)] Function marked as IO-only was called from a thread that disallows IO!  If this thread really should be allowed to make IO calls, adjust the call to base::ThreadRestrictions::SetIOAllowed() in this thread's startup.
0   Chromium Embedded Framework         0x0068b8cf base::debug::StackTrace::StackTrace() + 63
1   Chromium Embedded Framework         0x0068b92b base::debug::StackTrace::StackTrace() + 43
2   Chromium Embedded Framework         0x00719d52 logging::LogMessage::~LogMessage() + 82
3   Chromium Embedded Framework         0x00718a8b logging::LogMessage::~LogMessage() + 43
4   Chromium Embedded Framework         0x00832984 base::ThreadRestrictions::AssertIOAllowed() + 276
5   Chromium Embedded Framework         0x00810100 base::PlatformThread::Join(base::PlatformThreadHandle) + 48
6   Chromium Embedded Framework         0x008263a3 base::Thread::Stop() + 131
7   Chromium Embedded Framework         0x08413d8f content::InProcessRendererThread::~InProcessRendererThread() + 63
8   Chromium Embedded Framework         0x08413e0b content::InProcessRendererThread::~InProcessRendererThread() + 43
9   Chromium Embedded Framework         0x08413e5e content::InProcessRendererThread::~InProcessRendererThread() + 46
10  Chromium Embedded Framework         0x07bab824 base::DefaultDeleter<base::Thread>::operator()(base::Thread*) const + 68
11  Chromium Embedded Framework         0x07bab7aa base::internal::scoped_ptr_impl<base::Thread, base::DefaultDeleter<base::Thread> >::reset(base::Thread*) + 122
12  Chromium Embedded Framework         0x07b93bc9 scoped_ptr<base::Thread, base::DefaultDeleter<base::Thread> >::reset(base::Thread*) + 57
13  Chromium Embedded Framework         0x07b85dc8 content::RenderProcessHostImpl::~RenderProcessHostImpl() + 392
14  Chromium Embedded Framework         0x07b8632b content::RenderProcessHostImpl::~RenderProcessHostImpl() + 43
15  Chromium Embedded Framework         0x07b864be content::RenderProcessHostImpl::~RenderProcessHostImpl() + 46
16  Chromium Embedded Framework         0x00534d88 CefContentRendererClient::RunSingleProcessCleanupOnUIThread() + 872
17  Chromium Embedded Framework         0x00534888 CefContentRendererClient::RunSingleProcessCleanup() + 344
18  Chromium Embedded Framework         0x003d6ab5 CefContext::FinalizeShutdown() + 69
19  Chromium Embedded Framework         0x003d5b26 CefContext::Shutdown() + 694
20  Chromium Embedded Framework         0x003d5750 CefShutdown() + 512
21  Chromium Embedded Framework         0x0027dbe7 cef_shutdown + 39
22  CEFSimpleSample                     0x000c1a37 CefShutdown() + 39
23  CEFSimpleSample                     0x000baefc main + 388
24  libdyld.dylib                       0x96e33701 start + 1
25  ???                                 0x00000003 0x0 + 3

这是我的应用程序的一部分。断言在 CEFShutdown() 方法中失败,是一个框架方法:

// Entry point function for the browser process.
int main(int argc, char* argv[]) {
    // Provide CEF with command-line arguments.
    CefMainArgs main_args(argc, argv);

    // ClientHandler implements application-level callbacks. It will create the first
    // browser instance in OnContextInitialized() after CEF has initialized.
    CefRefPtr<ClientHandler> app(new ClientHandler);

    // Initialize the AutoRelease pool.
    NSAutoreleasePool* autopool = [[NSAutoreleasePool alloc] init];

    // Initialize the SimpleApplication instance.
    [SimpleApplication sharedApplication];

    // Specify CEF global settings here.
    CefSettings settings;
    settings.single_process = true;

    // Initialize CEF for the browser process.
    CefInitialize(main_args, settings, app.get(), NULL);

    // Create the application delegate.
    NSObject* delegate = [[SimpleAppDelegate alloc] init];
    [delegate performSelectorOnMainThread:@selector(createApplication:)
                               withObject:nil
                            waitUntilDone:NO];

    // Run the CEF message loop. This will block until CefQuitMessageLoop() is
    // called.
    CefRunMessageLoop();

    // Shut down CEF.
    CefShutdown();

    // Release the delegate.
    [delegate release];

    // Release the AutoRelease pool.
    [autopool release];

    return 0;
}

最佳答案

这是 CEF 的一个已知错误:

https://code.google.com/p/chromiumembedded/issues/detail?id=1182

Chromium 通常会将 UI 线程与 IO 线程区分开来,并且消息是将这些线程混淆的断言。与你自己的IO无关。

您需要查看堆栈以了解发生了什么。具有命名空间的函数通常属于 Chromium,而全局命名空间中的函数是 CEF 本身的一部分。与 CEF 相关的崩溃通常是由于嵌入 Chromium 的胶水......

有罪的函数可能是方法 RunSingleProcessCleanupOnUIThread CefContentRendererClient 的。顾名思义,它是在 UI 线程上运行的。

void CefContentRendererClient::RunSingleProcessCleanupOnUIThread() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

  // Clean up the single existing RenderProcessHost.
  content::RenderProcessHost* host = NULL;
  content::RenderProcessHost::iterator iterator(
      content::RenderProcessHost::AllHostsIterator());
  if (!iterator.IsAtEnd()) {
    host = iterator.GetCurrentValue();
    host->Cleanup();
    iterator.Advance();
    DCHECK(iterator.IsAtEnd());
  }
  DCHECK(host);

  // Clear the run_renderer_in_process() flag to avoid a DCHECK in the
  // RenderProcessHost destructor.
  content::RenderProcessHost::SetRunRendererInProcess(false);

  // Deletion of the RenderProcessHost object will stop the render thread and
  // result in a call to WillDestroyCurrentMessageLoop.
  // Cleanup() will cause deletion to be posted as a task on the UI thread but
  // this task will only execute when running in multi-threaded message loop
  // mode (because otherwise the UI message loop has already stopped). Therefore
  // we need to explicitly delete the object when not running in this mode.
  if (!CefContext::Get()->settings().multi_threaded_message_loop)
    delete host;
}

崩溃发生在函数的最底部。事实上,multi_threaded_message_loop 是 false(multi_threaded_message_loop 仅适用于 Windows),我们可以跟踪堆栈跟踪中的崩溃到 RenderProcessHostImpl 析构函数。

从代码和注释中可以清楚地看出,这是围绕 Chromium 进行的相当肮脏的黑客攻击,试图重现 Chromium 在其他地方所做的事情。我实际上认为 DCHECK(Chromium 断言宏)解决方法已经过时,因为这里设置为 false 的 g_run_renderer_in_process_ 未在析构函数中检查。

BrowserMainLoop::ShutdownThreadsAndCleanUp()中的以下评论可能会提供线索:

// Teardown may start in PostMainMessageLoopRun, and during teardown we
// need to be able to perform IO.
base::ThreadRestrictions::SetIOAllowed(true);
BrowserThread::PostTask(
    BrowserThread::IO, FROM_HERE,
    base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
             true));

解决方法是在调用 RunSingleProcessCleanupOnUIThread() 方法中的析构函数之前调用 base::ThreadRestrictions::SetIOAllowed(true);。不幸的是,您将需要为此目的重新编译 CEF,并且您不能在主函数中调用此表达式(在调用 CefShutdown() 之前),因为 CEF 不会公开这些 Chromium 内部结构。

关于c++ - CEF base::ThreadRestrictions::AssertIOAllowed() 断言在应用程序退出时失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27046870/

相关文章:

c++ - 使用 chrome 嵌入式框架 (CEF) 时如何处理事件消息?

c++ - 在 C++ 中使用算法头文件时出错

c++ - 从数组中删除最低输入?

c++ - 尝试使用非常量字符串通过 freopen 创建输出文件

c++ - 如何不同地编写reinterpret_cast <>

ios - 在 iOS 上禁用 'Don' t Reopen' 或 'Reopen' 对话框

xcode - Snow Leopard 的 OpenMP 链接器库?

javascript - 在 node-webkit 中打印没有 "print dialogue"

swift - #selector 在 NSMenuItem 中看不到我自己创建的方法

javascript - WPF/ChromiumWebBrowser 执行 Javascript 函数(带参数!)