开发者

C++ - Clutter 1.0 - calling function from thread causes segfault

开发者 https://www.devze.com 2023-01-18 10:15 出处:网络
I am struggling with calling a clutter function from an extra thread. I use boost::thread for threading and the clutter library 1.0.

I am struggling with calling a clutter function from an extra thread. I use boost::thread for threading and the clutter library 1.0.

To be specific, the thread contains a looped function that emits boost::signals2::signal with parameters of x and y coordinates every once in a while. That signal is connected to a function that hands those variables to clutter, i.e. x,y in

clutter_stage_get_actor_at_pos(CLUTTER_STAGE(actor), CLUTTER_PICK_ALL, x, y);

And that is where i get a segfault.

Apparently clutter has some thread-handling routines. I tried calling

g_thread_init(NULL);

clutter_threads_init();

before starting clutter_main(). I also tried enclosing the clutter function in

clutter_threads_enter();

clutter_stage_get_actor开发者_Python百科_at_pos(CLUTTER_STAGE(actor), CLUTTER_PICK_ALL, x, y);

clutter_threads_leave();

but that does also not do the trick..

Every hint is appreciated, thank you in advance!

Addendum

I just forged a minimal sample of what I am trying to do. I already 'protected' the clutter_main() routine as suggested. Some functions of clutter seem to work (e.g setting stage color or setting actor position) from the seperate thread. Is there still something wrong with my code?

#include <clutter/clutter.h>
#include <boost/thread.hpp>


ClutterActor *stage;
ClutterActor* rect = NULL;


void receive_loop()
{
while(1)
{
    sleep(1);
    clutter_threads_enter();

    ClutterActor* clicked =  clutter_stage_get_actor_at_pos(CLUTTER_STAGE(stage), CLUTTER_PICK_ALL,300, 500);
    
    clutter_threads_leave();
}

}


int main(int argc, char *argv[]) 
{

    clutter_init(&argc, &argv);

g_thread_init(NULL);
clutter_threads_init();


    stage = clutter_stage_get_default();
    clutter_actor_set_size(stage, 800, 600);


rect = clutter_rectangle_new();
clutter_actor_set_size(rect, 256, 128);
clutter_actor_set_position(rect, 300, 500);
clutter_group_add (CLUTTER_GROUP (stage), rect);    


    clutter_actor_show(stage);


boost::thread thread = boost::thread(&receive_loop);


clutter_threads_enter();
    clutter_main();
clutter_threads_leave();

    return 0;
}


Well, I think I found the answer..

Clutter Docs Gerneral

It says in section "threading model":

The only safe and portable way to use the Clutter API in a multi-threaded environment is to never access the API from a thread that did not call clutter_init() and clutter_main().

The common pattern for using threads with Clutter is to use worker threads to perform blocking operations and then install idle or timeour sources with the result when the thread finished.

Clutter provides thread-aware variants of g_idle_add() and g_timeout_add() that acquire the Clutter lock before invoking the provided callback: clutter_threads_add_idle() and clutter_threads_add_timeout().

So my correction to the minimal sample code would be to alter the receive_loop() to

void receive_loop()
{
while(1)
{
    sleep(1);

    int pos[2];
    pos[0] = 400;
    pos[1] = 200;
    
    clutter_threads_add_idle_full (G_PRIORITY_HIGH_IDLE,
                             get_actor,
                             &pos,
                             NULL);
}
}

and to add the get_actor function (as in the example code on the menitioned doc page)

static gboolean
get_actor (gpointer data)
{
    int* pos = (int*) data;
    ClutterActor* clicked = clutter_stage_get_actor_at_pos(CLUTTER_STAGE(stage), CLUTTER_PICK_ALL, pos[0], pos[1]);

    return FALSE;
}

clutter_threads_add_idle_full takes care of thread lock etc..


I struggled with a very similar situation in the Python bindings for clutter. I was never able to make the Clutter thread support work the way I wanted.

What finally did the trick was using an idle proc (gobject.idle_add in python) to push the work I needed done into the main clutter thread. That way I have only 1 thread making clutter calls and everything is fine.


I played with your code and it seems you are doing everything ok, though I'm no expert in Clutter. I also ran your program under gdb and some interesting things showed up:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb799db70 (LWP 3023)]
0x002d97c6 in glDisable () from /usr/lib/nvidia-current/libGL.so.1
(gdb) thread apply all bt

Thread 2 (Thread 0xb799db70 (LWP 3023)):
#0  0x002d97c6 in glDisable () from /usr/lib/nvidia-current/libGL.so.1 
#1  0x001b3ec3 in cogl_disable_fog () from /usr/lib/libclutter-glx-1.0.so.0
#2  0x0018b00a in ?? () from /usr/lib/libclutter-glx-1.0.so.0
#3  0x0019dc82 in clutter_stage_get_actor_at_pos () from /usr/lib/libclutter-glx-1.0.so.0
#4  0x080498de in receive_loop () at seg.cpp:19

Apparently the crash happened on glDisable () from /usr/lib/nvidia-current/libGL.so.1. Notice that I use NVIDIA's OpenGL driver on my GeForce 8600 GT.

Can you confirm that your application also crashes on computers with other video cards (not NVIDIA)? I doubt the crash is due to a bug on NVIDIA's OpenGL implementation.

For me it seems that *clutter_threads_enter/leave()* is not protecting *clutter_stage_get_actor_at_pos()* since I tested *receive_loop()* being called as a callback:

g_signal_connect(stage, "button-press-event", G_CALLBACK(receive_loop), NULL);

so we know that your code seems to be ok.

I encourage you to send your question to Clutter discussion and help mailing list: clutter-app-devel-list

a mailing list for application developers using Clutter, its integration libraries or toolkits based on Clutter.


You can either use clutter_threads_add_idle to update ClutterActor or you need to fix the clutter_threads_enter/leave to switch OpenGL context as well so that you can use it inside a thread.

The crash

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb799db70 (LWP 3023)]
0x002d97c6 in glDisable () from /usr/lib/nvidia-current/libGL.so.1
(gdb) thread apply all bt

Thread 2 (Thread 0xb799db70 (LWP 3023)):
#0  0x002d97c6 in glDisable () from /usr/lib/nvidia-current/libGL.so.1 
#1  0x001b3ec3 in cogl_disable_fog () from /usr/lib/libclutter-glx-1.0.so.0
#2  0x0018b00a in ?? () from /usr/lib/libclutter-glx-1.0.so.0
#3  0x0019dc82 in clutter_stage_get_actor_at_pos () from /usr/lib/libclutter-glx-1.0.so.0
#4  0x080498de in receive_loop () at seg.cpp:19

is because the calling thread didn't acquire OpenGL context so it crashed.

0

精彩评论

暂无评论...
验证码 换一张
取 消