2014-11-20 54 views
1

我有一個基於提供的cefsample應用程序的OSX的簡單CEF應用程序。一個值得注意的變化是我在單進程模式下運行(settings.single_process = true)。由於斷言失敗,我在退出時崩潰。奇怪的是,這種崩潰也發生在發佈版本中,而不僅僅是調試版本。CEF base :: ThreadRestrictions :: AssertIOAllowed()聲明在應用程序退出時失敗

任何人都可以(CEF大師)幫助我理解問題出在哪裏? stacktrace說我從一個不允許IO的線程調用「IO-only」函數。我正在做的唯一的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; 
} 

回答

2

這是CEF的一個已知的錯誤:

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

鉻通常區別於IO UI線程線程,並且該消息是這些混淆的斷言。這與你自己的IO無關。

您需要查看堆棧以瞭解發生了什麼。具有名稱空間的函數通常屬於Chromium,而全局名稱空間中的函數是CEF本身的一部分。與CEF相關的崩潰通常是由於嵌入鉻的膠水造成的......

有罪功能可能是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 assert macro)解決方法已過時,因爲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)); 

修復程序可能是RunSingleProcessCleanupOnUIThread()方法調用析構函數之前調用base::ThreadRestrictions::SetIOAllowed(true);。不幸的是,您需要爲此重新編譯CEF,並且您不能在主函數中調用此表達式(在調用CefShutdown()之前),因爲CEF不公開這些Chromium內部函數。

+0

很棒的回答。謝謝。 – mikejonesguy 2014-11-21 16:31:49

+0

我有類似的問題,但在我的情況下,如果我使用base :: ThreadRestrictions :: SetIOAllowed(true);關機之前我得到錯誤:未聲明的標識符 – Swati 2017-03-08 08:48:32