我有一个简单的 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/