WebKit在工作线程上运行

时间:2015-11-30 23:47:19

标签: c++ multithreading webkit

我有一个需要在线程上呈现HTML的C ++应用程序。我已经研究了QtWebKit和Webkit2Gtk +并遇到了同样的问题:经过大约3-4次迭代后,它崩溃了。

基本设置是这样的(在本例中使用Webkit2Gtk +):

WebKitWebView *HtmlView;

void destroyHtmlWindowCb( GtkWidget *widget, GtkWidget *window ) {
    gtk_main_quit();
}

gboolean closeHtmlViewCb( WebKitWebView *webView, GtkWidget *window ) {
    webkit_web_view_stop_loading( webView );
    gtk_widget_destroy( window );
    return true;
}

void RendererThread( boost::barrier &render_barrier ) {
    gtk_init( nullptr, nullptr );
    GtkWidget *HtmlWindow;

    while( true ) {
        render_barrier.count_down_and_wait();

        HtmlWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
        HtmlView = WEBKIT_WEB_VIEW(webkit_web_view_new());

        g_signal_connect( HtmlView, "close", G_CALLBACK(closeHtmlViewCb), HtmlWindow );
        g_signal_connect( HtmlWindow, "destroy", G_CALLBACK(destroyHtmlWindowCb), nullptr );

        gtk_container_add( GTK_CONTAINER(HtmlWindow), GTK_WIDGET(HtmlView) );
        gtk_widget_show( GTK_WIDGET(HtmlView) );

        webkit_web_view_load_uri( HtmlView, "http://www.stackoverflow.com/" );

        gtk_window_set_default_size( GTK_WINDOW(HtmlWindow), 1920, 1080 );
        gtk_window_fullscreen( GTK_WINDOW(HtmlWindow) );
        gtk_widget_show( HtmlWindow );

        std::cout << "Calling gtk_main()" << std::endl;
        gtk_main();
    }
}

void EventHandlerThread( boost::barrier &render_barrier ) {
    while( true ) {
        render_barrier.count_down_and_wait();

        std::this_thread::sleep_for( std::chrono::seconds( 15 ) );

        g_signal_emit_by_name( HtmlView, "close" );
    }
}

int main() {
    boost::barrier render_barrier( 2 );

    std::thread Renderer( RendererThread, std::ref(render_barrier) );
    Renderer.detach();

    std::thread EventHandler( EventHandlerThread, std::ref(render_barrier) );
    EventHandler.detach();

    //... sleep forever as far as this example is concerned

    return 0;
}

这是真实程序的精简版,但任何竞争条件/线程安全问题都应准确表示。

程序在调用gtk_main()时总会崩溃,这是在stderr中生成的:

...
Calling gtk_main()
...
Calling gtk_main()
Error sending IPC message: Connection reset by peer
Nov 30 16:27:50 gmbase xinit[9541]: /usr/bin/xinit: connection to X server lost
Nov 30 16:27:50 gmbase org.a11y.atspi.Registry[9561]: XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0.0"
Nov 30 16:27:50 gmbase org.a11y.atspi.Registry[9561]: after 21 requests (19 known processed) with 0 events remaining.
Nov 30 16:27:50 gmbase xinit[9541]: waiting for X server to shut down (II) Server terminated successfully (0). Closing log file.
Nov 30 16:27:50 gmbase systemd-coredump[9646]: Process 9545 (glassmedia-debu) of user 0 dumped core.

Stack trace of thread 9548:
#0  0x00007fcbe0e22970 _ZNK3WTF10StringImpl12hashSlowCaseEv (libjavascriptcoregtk-4.0.so.18)
#1  0x00007fcbe0e15bf8 _ZN3WTF9HashTableIPNS_10StringImplES2_NS_17IdentityExtractorENS_10StringHashENS_10HashTraitsIS2_EES6_E6rehashEjPS2_ (libjavascriptcoregtk-4.0.so.18)
#2  0x00007fcbe0e14c3b _ZN3WTF16AtomicStringImpl11addSlowCaseERNS_10StringImplE (libjavascriptcoregtk-4.0.so.18)
#3  0x00007fcbe36fc4ee n/a (libwebkit2gtk-4.0.so.37)
#4  0x00007fcbe372dd63 n/a (libwebkit2gtk-4.0.so.37)
#5  0x00007fcbe374dfdc n/a (libwebkit2gtk-4.0.so.37)
#6  0x00007fcbe3719743 n/a (libwebkit2gtk-4.0.so.37)
#7  0x00007fcbe3719aec n/a (libwebkit2gtk-4.0.so.37)
#8  0x00007fcbe39c6f13 n/a (libwebkit2gtk-4.0.so.37)
#9  0x00007fcbe3704359 n/a (libwebkit2gtk-4.0.so.37)
#10 0x00007fcbe37c4ae2 n/a (libwebkit2gtk-4.0.so.37)
#11 0x00007fcbe370057b n/a (libwebkit2gtk-4.0.so.37)
#12 0x00007fcbe3700f9b n/a (libwebkit2gtk-4.0.so.37)
#13 0x00007fcbe4dea28f n/a (libwebkit2gtk-4.0.so.37)
#14 0x00007fcbe0e3591c _ZN3WTF15GMainLoopSource12voidCallbackEv (libjavascriptcoregtk-4.0.so.18)
#15 0x00007fcbe0e342ba _ZN3WTF15GMainLoopSource18voidSourceCallbackEPS0_ (libjavascriptcoregtk-4.0.so.18)
#16 0x00007fcbe0352c7a g_main_context_dispatch (libglib-2.0.so.0)
#17 0x00007fcbe0353020 n/a (libglib-2.0.so.0)
#18 0x00007fcbe0353342 g_main_loop_run (libglib-2.0.so.0)
#19 0x00007fcbe2af32a5 gtk_main (libgtk-3.so.0)
#20 0x0000000000477ec9 _ZN10Glassmedia7Display6renderEv (glassmedia-debug)
#21 0x0000000000498dd9 _ZN10Glassmedia14RendererThreadESt10shared_ptrINS_7DisplayEERN5boost7barrierE (glassmedia-debug)
#22 0x0000000000460739 _ZNSt12_Bind_simpleIFPFvSt10shared_ptrIN10Glassmedia7DisplayEERN5boost7barrierEES3_St17reference_wrapperIS5_EEE9_M_invokeIJLm0ELm1EEEEvSt12_Index_tupleIJXspT_EEE (glassmedia-debug)
#23 0x00007fcbe0040350 execute_native_thread_routine (libstdc++.so.6)
#24 0x00007fcbdf85d4a4 start_thread (libpthread.so.0)
#25 0x00007fcbdf59b13d __clone (libc.so.6)

Stack trace of thread 9549:
#0  0x00007fcbdf86307f pthread_cond_wait@@GLIBC_2.3.2 (libpthread.so.0)
#1  0x00007fcbe003aefc __gthread_cond_wait (libstdc++.so.6)
#2  0x00000000004991c3 _ZN10Glassmedia18EventHandlerThreadESt10shared_ptrINS_7DisplayEERNS_12EventCourierERN5boost7barrierE (glassmedia-debug)
#3  0x0000000000460801 _ZNSt12_Bind_simpleIFPFvSt10shared_ptrIN10Glassmedia7DisplayEERNS1_12EventCourierERN5boost7barrierEES3_St17reference_wrapperIS4_ESB_IS7_EEE9_M_invokeIJLm0ELm1ELm2EEEEvSt12_Index_tupleIJXspT_EEE (glassmedia-debug)
#4  0x00007fcbe0040350 execute_native_thread_routine (libstdc++.so.6)
#5  0x00007fcbdf85d4a4 start_thread (libpthread.so.0)
#6  0x00007fcbdf59b13d __clone (libc.so.6)

Stack trace of thread 9566:
#0  0x00007fcbdf59218d poll (libc.so.6)
#1  0x00007fcbe0352fbc n/a (libglib-2.0.so.0)
#2  0x00007fcbe0353342 g_main_loop_run (libglib-2.0.so.0)
#3  0x00007fcbe0e05dd5 n/a (libjavascriptcoregtk-4.0.so.18)
#4  0x00007fcbe0e325fa n/a (libjavascriptcoregtk-4.0.so.18)
#5  0x00007fcbdf85d4a4 start_thread (libpthread.so.0)
#6  0x00007fcbdf59b13d __clone (libc.so.6)

Stack trace of thread 9567:
#0  0x00007fcbdf59218d poll (libc.so.6)
#1  0x00007fcbe0352fbc n/a (libglib-2.0.so.0)
#2  0x00007fcbe0353342 g_main_loop_run (libglib-2.0.so.0)
#3  0x00007fcbe0e05dd5 n/a (libjavascriptcoregtk-4.0.so.18)
#4  0x00007fcbe0e325fa n/a (libjavascriptcoregtk-4.0.so.18)
#5  0x00007fcbdf85d4a4 start_thread (libpthread.so.0)
#6  0x00007fcbdf59b13d __clone (libc.so.6)

Stack trace of thread 9639:
#0  0x00007fcbdf86665d __nanosleep (libpthread.so.0)
#1  0x00007fcbe0e41b3c _ZN7bmalloc4Heap8scavengeERSt11unique_lockINS_11StaticMutexEENSt6chrono8durationIlSt5ratioILl1ELl1000EEEE (libjavascriptcoregtk-4.0.so.18)
#2  0x00007fcbe0e41c5f _ZN7bmalloc4Heap18concurrentScavengeEv (libjavascriptcoregtk-4.0.so.18)
#3  0x00007fcbe0e429ae _ZN7bmalloc9AsyncTaskINS_4HeapEMS1_FvvEE13threadRunLoopEv (libjavascriptcoregtk-4.0.so.18)
#4  0x00007fcbe0040350 execute_native_thread_routine (libstdc++.so.6)
#5  0x00007fcbdf85d4a4 start_thread (libpthread.so.0)
#6  0x00007fcbdf59b13d __clone (libc.so.6)

Stack trace of thread 9545:
#0  0x00007fcbdf85e70d pthread_join (libpthread.so.0)
#1  0x00007fcbe0040267 __gthread_join (libstdc++.so.6)
#2  0x000000000045ed55 main (glassmedia-debug)
#3  0x00007fcbdf4d2610 __libc_start_main (libc.so.6)
#4  0x000000000045dc79 _start (glassmedia-debug)

Stack trace of thread 9569:
#0  0x00007fcbdf59218d poll (libc.so.6)
#1  0x00007fcbe0352fbc n/a (libglib-2.0.so.0)
#2  0x00007fcbe0353342 g_main_loop_run (libglib-2.0.so.0)
#3  0x00007fcbe0e05dd5 n/a (libjavascriptcoregtk-4.0.so.18)
#4  0x00007fcbe0e325fa n/a (libjavascriptcoregtk-4.0.so.18)
#5  0x00007fcbdf85d4a4 start_thread (libpthread.so.0)
#6  0x00007fcbdf59b13d __clone (libc.so.6)

Stack trace of thread 9547:
#0  0x00007fcbdf59b733 epoll_wait (libc.so.6)
#1  0x00007fcbe6298f15 n/a (libev.so.4)
#2  0x00007fcbe629b4b9 ev_run (libev.so.4)
#3  0x000000000047e7c1 ev_loop (glassmedia-debug)
#4  0x0000000000498ae4 _ZN10Glassmedia21EventSubscriberThreadERNS_12EventCourierE (glassmedia-debug)
#5  0x000000000045f086 _ZNSt12_Bind_simpleIFPFvRN10Glassmedia12EventCourierEESt17reference_wrapperIS1_EEE9_M_invokeIJLm0EEEEvSt12_Index_tupleIJXspT_EEE (glassmedia-debug)
#6  0x00007fcbe0040350 execute_native_thread_routine (libstdc++.so.6)
#7  0x00007fcbdf85d4a4 start_thread (libpthread.so.0)
#8  0x00007fcbdf59b13d __clone (libc.so.6)

Stack trace of thread 9572:
#0  0x00007fcbdf59218d poll (libc.so.6)
#1  0x00007fcbe0352fbc n/a (libglib-2.0.so.0)
#2  0x00007fcbe0353342 g_main_loop_run (libglib-2.0.so.0)
#3  0x00007fcbe0e05dd5 n/a (libjavascriptcoregtk-4.0.so.18)
#4  0x00007fcbe0e325fa n/a (libjavascriptcoregtk-4.0.so.18)
#5  0x00007fcbdf85d4a4 start_thread (libpthread.so.0)
#6  0x00007fcbdf59b13d __clone (libc.so.6)

QtWebKit的代码非常相似;相同的结果。

在真实的程序中,我的测试在Reddit和CNN之间循环。就一个网站造成崩溃而另一个网站而言,没有任何模式可以辨别出来。

请忽略任何看起来很愚蠢的主线程永远等待的事情。在真实的节目中,我有我的理由。

感谢您对此问题的任何帮助。我现在已经工作了很长时间。

1 个答案:

答案 0 :(得分:1)

我发现,只要我使用QWebEngine(QtWebKit的Google Chrome分支),问题就会消失。代码变得更加简单:

#include <QApplication>
#include <QWebEngineView>

QWebEngineView *HtmlView;

void RendererThread( boost::barrier &render_barrier, int main_argc, char **main_argv ) {
    QApplication app( main_argc, main_argv );

    while( true ) {
        render_barrier.count_down_and_wait();

        HtmlView = new QWebEngineView();
        HtmlView->setAttribute( Qt::WA_DeleteOnClose );

        HtmlView->load( QUrl( "http://www.stackoverflow.com/" ) );

        HtmlView->resize( 1920, 1080 );
        HtmlView->raise();
        HtmlView->move( 0, 0 );

        HtmlView->showFullscreen();

        app.exec();
    }
}

void EventHandlerThread( boost::barrier &render_barrier ) {
    while( true ) {
        render_barrier.count_down_and_wait();

        std::this_thread::sleep_for( std::chrono::seconds( 15 ) );

        HtmlView->stop();
        HtmlView->close();
    }
}

int main( int argc, char *argv[] ) {
    boost::barrier render_barrier( 2 );

    std::thread Renderer( RendererThread, std::ref(render_barrier), argc, argv );
    Renderer.detach();

    std::thread EventHandler( EventHandlerThread, std::ref(render_barrier) );
    EventHandler.detach();

    //... sleep forever as far as this example is concerned

    return 0;
}

我在Arch Linux上的qt5-webengine包下安装了QWebEngine。

程序需要Qt5WebEngineWidgets的cflags和libs来编译:

g++ -std=c++11 -Wall `pkg-config --cflags Qt5WebEngineWidgets` webkit_test.cpp -o webkit_test `pkg-config --libs Qt5WebEngineWidgets` -pthread