Каир - многопоточность - зависание во время cairo_image_surface_create - PullRequest
0 голосов
/ 26 сентября 2019

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

Однако через некоторое время (например, сохраняется 20 изображений) приложение застревает в _cairo_atomic_init_once_enter с cairo-atomic-private.h.

Вот трассировка стека из Visual Studio:

[Inline Frame] app.exe!_cairo_atomic_init_once_enter(unsigned int *) Line 409   C
app.exe!_cairo_image_spans_compositor_get() Line 3135   C
[Inline Frame] app.exe!_cairo_image_surface_init(_cairo_image_surface *) Line 176   C
app.exe!_cairo_image_surface_create_for_pixman_image(pixman_image * pixman_image=0x0000023c1d1f31f0, pixman_format_code_t pixman_format=PIXMAN_a8r8g8b8) Line 197   C
app.exe!_cairo_image_surface_create_with_pixman_format(unsigned char * data=0x0000000000000000, pixman_format_code_t pixman_format=PIXMAN_a8r8g8b8, int width, int height, int stride=-1) Line 355  C
app.exe!cairo_image_surface_create(_cairo_format format, int width, int height) Line 403    C

, и я звоню:

surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, int(w), int(h));

Мой параллельный цикл выполняется через:

std::vector<int> xSeq(countX); 
std::iota(std::begin(xSeq), std::end(xSeq), 0); // Fill with 0, 1, ..., countX.
std::for_each(std::execution::par, std::begin(xSeq), std::end(xSeq), [&](auto x)
{
    //create cairo surface, write to it, store it and release it
}

Если я запускаю последовательную версию, все работает правильно.

Редактировать: Чтобы сохранить поверхность для изображения, я не использую встроенную PNG-заставку.У меня есть своя собственная реализация, основанная на:

cairo_surface_flush(surface);
data = cairo_image_surface_get_data(surface);

data содержит необработанные данные из cairo, и я обрабатываю их вручную и сохраняю в собственной системе сжатия.

В некоторыхВ некоторых случаях я использую ту же систему для «ввода» данных в поверхность Каира.Я получаю указатель data, вручную переписываю несколько пикселей и вызываю cairo_surface_mark_dirty(surface), чтобы уведомить Каир об изменении.

1 Ответ

1 голос
/ 27 сентября 2019

Это не совсем ответ, но наблюдаемое вами поведение должно быть невозможным.

_cairo_image_traps_compositor_get имеет переменную cairo_atomic_once_t, которая используется для защиты некоторой инициализации.Поскольку он статический, мы можем быть уверены, что никакой другой код не коснется этой переменной.

https://github.com/freedesktop/cairo/blob/52a7c79fd4ff96bb5fac175f0199819b0f8c18fc/src/cairo-image-compositor.c#L1270-L1304

_cairo_atomic_init_once_enter проверяет, инициализирована ли once, и затем просто возвращает 0 /false.Поскольку вы говорите, что у вас уже было 20 успешных вызовов, инициализация уже должна быть выполнена.Иначе, 20 других вызовов не должны были работать.

https://github.com/freedesktop/cairo/blob/52a7c79fd4ff96bb5fac175f0199819b0f8c18fc/src/cairo-atomic-private.h#L398-L411

В соответствии с вышесказанным ... это не должно быть возможным, верно?Если что-то не перезаписывает какую-то память, к которой оно не должно прикасаться, и значение once будет повреждено или что-то в этом роде.Кроме того, это некая неправильная компиляция, которая происходит по причинам, которые я не понимаю.Собирали ли вы Каир самостоятельно или откуда его взяли?

...