запустить функцию в другом потоке, чем графический интерфейс - PullRequest
1 голос
/ 08 июня 2010

У меня есть простое приложение C / GTK +.У меня есть функция в этом приложении, которая загружает изображение в виджете gtkimageview:

gboolean 
main_win_open( MainWin* mw, const char* file_path)
{
  ...       
  //loading and displaing image in gtkimageview
  ...
}

Загрузка изображения работает, но мне нужно запустить эту функцию в другом потоке, а не в главной форме графического интерфейса;

Iесть функция:

void*
argument_thread(void *args)
{
  Data *data = (Data*)args;
  gdk_threads_enter();
  main_win_open (data->win,data->argv);
  gdk_threads_leave();
}

Данные это структура для main_win_open аргументов функции:

typedef struct _Data
{
  MainWin *win;
  char* argv;
} Data;

Затем в основной функции я создаю поток и запускаю его:

int main(int argc, char** argv)
{
    GError*   err;
    GThread*  thread;   
    Data data;
    MainWin *win;

    // init thread support
    if(!g_thread_supported())
        g_thread_init(NULL);
        gdk_threads_init();

    // init GTK+
    gtk_init (&argc, &argv);

    win = (MainWin*)main_win_new();
    gtk_widget_show(GTK_WIDGET(win));

    data.win = win;
    data.argv = argv[1];

    if (argc == 2)
    {
       thread = g_thread_create((GThreadFunc)argument_thread,&data,FALSE, &err);
    }

    gdk_threads_enter();
    gtk_main();
    gdk_threads_leave();
}

Но когда я пытаюсь запустить приложение из командной строки и загрузить изображение большого размера, графический интерфейс блокируется.

Что не так?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 10 июня 2010

Если вы вызовете gdk_threads_enter () до , вы начнете загружать изображение, тогда графический интерфейс будет зависать и не отвечать на запросы во время загрузки изображения. По сути, тот же результат вы получаете, сначала загрузив изображение, а затем создав графический интерфейс в одном потоке. Вероятно, вы захотите вызвать gdk_threads_enter () после трудоемкой задачи загрузки изображения и требовать блокировки GDK только при быстром обновлении графического интерфейса.

Блокировка GDK необходима, потому что GTK + не является потокобезопасным. Однако реализация X11 (и, вероятно, также Mac) является поточно-ориентированной, что означает, что любой API может использовать любой API (но, конечно, только один за раз, следовательно, блокировку).

Windows API, с другой стороны, не может использоваться таким образом ни из какого потока, и, следовательно, также не является версией GTK + для Windows. Не разбираясь в деталях о Windows API, будет хорошей идеей вызывать GTK + только из одного потока. Это не значит, что о многопоточных приложениях не может быть и речи. Вы все еще можете загрузить изображение в другом потоке и затем использовать, например, gtk_idle_add () для обновления графического интерфейса в основном потоке.

1 голос
/ 17 июня 2010

Re код размещен здесь http://pastebin.com/BkLJ7UkR

Я не думаю, что вы МОЖЕТЕ делать подобные вещи из основного потока ... (Ну, конечно, чтение из файла, но не GdkPixbuf)

что вам нужно сделать, это разделить ваш main_win_open на две части: ту, которая выполняет чтение файла, и ту, которая загружает данные в загрузчик pixbuf, затем вызывает вторую функцию через g_idle_add () (которая является поточно-безопасной, это ' добавлю обратный вызов в mainloop)

Если вы хотите сделать это, я бы предложил загрузить все изображение в память за один раз, а затем передать его через g_idle_add

Однако я сильно сомневаюсь, что что-то из этого необходимо ... насколько велико изображение, которое вы загружаете, чтобы оно потратило хотя бы отдаленно заметное количество времени на его загрузку? (По сути, я думаю, что вы делаете неправильно, когда используете потоки, когда они очень не нужны)

0 голосов
/ 08 июня 2010

В документации от gdk_threads_enter ():

"Этот макрос отмечает начало критическая секция, в которой GDK и GTK + функции можно вызывать безопасно и не вызывая условий гонки. Только одна нить за раз может быть в такой критический раздел. "

Если я не ошибаюсь, это причина, по которой ваше приложение все еще блокируется. Для приложений GThread вызовы gdk_threads_enter / _leave не нужны, поэтому попробуйте удалить их.

...