我有一个简单的OSX应用程序,它基于提供的cefsample应用程序。一个值得注意的变化是我在单进程模式(settings.single_process = true
)中运行。由于断言失败,我在退出时遇到了崩溃。奇怪的是,此崩溃也发生在发布版本中,而不仅仅是调试版本。
任何人(CEF大师)都可以帮我理解这里的问题是什么吗?堆栈跟踪表示我正在调用“仅限IO”"来自不允许IO的线程的函数。我唯一做的就是我从应用包中加载静态html文件。这似乎不应该需要特殊处理。但是,好吧,让我们假设它确实要求我在这个线程的启动中调整对base :: ThreadRestrictions :: SetIOAllowed()的调用"正如断言错误中所建议的那样 - 我不知道如何或在何处这样做。
这是stacktrace:
[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;
}
答案 0 :(得分:2)
这是CEF的已知错误:
https://code.google.com/p/chromiumembedded/issues/detail?id=1182
Chromium通常将UI线程与IO线程区分开来,而消息是这些消息混淆的断言。它与您自己的IO无关。
您需要查看堆栈以了解正在发生的事情。具有命名空间的函数通常属于Chromium,而全局命名空间中的函数是CEF本身的一部分。与CEF相关的崩溃往往是由于嵌入铬的粘合剂......
guilty函数可能是CefContentRendererClient的方法RunSingleProcessCleanupOnUIThread
。该名称暗示它意味着在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
是假的(multi_threaded_message_loop
仅适用于Windows),我们可以跟踪堆栈跟踪中的崩溃到RenderProcessHostImpl析构函数。
从代码和评论中可以清楚地看出,这是围绕Chromium的一个肮脏的黑客,试图重现Chromium在别处做的事情。我实际上相信DCHECK(Chromium断言宏)解决方法已过时,因为g_run_renderer_in_process_
设置为false,这里不会在析构函数中检查。
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));
修复可能是在base::ThreadRestrictions::SetIOAllowed(true);
方法中调用析构函数之前调用RunSingleProcessCleanupOnUIThread()
。不幸的是,您需要为此目的重新编译CEF,并且您不能在主函数中调用此表达式(在调用CefShutdown()
之前),因为CEF不会公开这些Chromium内部。