Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

离线画布在多线程情况下会崩溃 #917

Open
Tracker647 opened this issue Dec 12, 2024 · 1 comment
Open

离线画布在多线程情况下会崩溃 #917

Tracker647 opened this issue Dec 12, 2024 · 1 comment

Comments

@Tracker647
Copy link

Tracker647 commented Dec 12, 2024

项目在服务器上部署后运行不到20分钟就出现偶现崩溃现象,gdb排查到是一个图片显示模块里面调用了自己做的resize函数,这个图片resize是我用离线画布实现的,离线画布调用canvas_offline_destroy时,在vgcanvas这一层引发了崩溃。

这个模块包括SDK和自定义控件部分,SDK里有一个线程,自定义控件有一个定时器,都调用了这个resize函数,之前尝试把这个resize api换到单线程环境运行了几个小时,没发现崩溃现象,就怀疑是多线程的问题,于是自己再把demo改成多线程试了下,果然复现出和项目类似的现象。

请问这种情况是为什么?如果canvas_offline的api不是线程安全的,麻烦在官网文档上添注一下。

测试环境:在Ubuntu 20.04, 虚拟机上scons LINUX_FB=true
Demo:

#include "awtk.h"
#include "common/navigator.h"
#include "tkc/thread.h"


#ifndef APP_SYSTEM_BAR
#define APP_SYSTEM_BAR ""
#endif /*APP_SYSTEM_BAR*/

#ifndef APP_BOTTOM_SYSTEM_BAR
#define APP_BOTTOM_SYSTEM_BAR ""
#endif /*APP_BOTTOM_SYSTEM_BAR*/

#ifndef APP_START_PAGE
#define APP_START_PAGE "home_page"
#endif /*APP_START_PAGE*/

typedef struct {
    bool_t running;
    tk_thread_t* thread;
    tk_thread_entry_t entry;
    void *args;
} my_thread_t;

my_thread_t* my_thread_create(tk_thread_entry_t entry, void* args) {
  my_thread_t* th = TKMEM_ZALLOC(my_thread_t);
  return_value_if_fail(th != NULL, NULL);
  th->thread = tk_thread_create(entry, args);
  th->entry = entry;
  th->args = args;
  return th;
}

ret_t my_thread_start(my_thread_t *th){
  return_value_if_fail(th != NULL, RET_BAD_PARAMS);
  if(!th->running){
    th->running = TRUE;
    return_value_if_fail(RET_OK == tk_thread_start(th->thread), RET_FAIL);
  }
  return RET_OK;
}

ret_t my_thread_reset(my_thread_t *th){
  return_value_if_fail(th != NULL, RET_BAD_PARAMS);
  if (th->running) {
    th->running = FALSE;
    return_value_if_fail(RET_OK == tk_thread_join(th->thread), RET_FAIL);
  }
  tk_thread_destroy(th->thread);
  th->thread = tk_thread_create(th->entry, th->args);
  return RET_OK;
}

ret_t my_thread_destroy(my_thread_t* th) {
    return_value_if_fail(th != NULL, RET_BAD_PARAMS);
    if (th->running) {
        th->running = FALSE;
        return_value_if_fail(RET_OK == tk_thread_join(th->thread), RET_FAIL);
    }
    tk_thread_destroy(th->thread);
    TKMEM_FREE(th);
    return RET_OK;
}


my_thread_t *g_thread1 = NULL;
my_thread_t *g_thread2 = NULL;

/**
 * 注册自定义控件
 */
static ret_t custom_widgets_register(void) {

  return RET_OK;
}

/**
 * 当程序初始化完成时调用,全局只触发一次。
 */
static ret_t application_on_launch(void) {

  return RET_OK;
}

/**
 * 当程序退出时调用,全局只触发一次。
 */
static ret_t application_on_exit(void) {

  return RET_OK;
}



/**
 * @brief resize bitmap and delete old one
 * 
 * @param _bmp 
 * @param new_width 
 * @param new_height 
 * @return ret_t 
 */
static ret_t helper_bitmap_resize(bitmap_t **_bmp, int new_width, int new_height) {
    bitmap_t *bmp = *_bmp;
    if(bmp->w == new_width && bmp->h == new_height){
      return RET_OK;
    }
    // printf("%d %d | %d %d\r\n", bmp->w, new_width, bmp->h, new_height);
    canvas_t *new_bmp_canvas = canvas_offline_create(new_width, new_height, (bitmap_format_t)bmp->format);
    rect_t dst_r = rect_init(0, 0, new_width, new_height);
    rect_t src_r = rect_init(0, 0, bmp->w, bmp->h);
    canvas_draw_image(new_bmp_canvas, bmp, &src_r, &dst_r);
    bitmap_t *new_bmp = canvas_offline_get_bitmap(new_bmp_canvas);
    bitmap_destroy(bmp);
    *_bmp = bitmap_clone(new_bmp);
    canvas_offline_destroy(new_bmp_canvas);
    return RET_OK;
}



void *thread_func1(void *args){
    while(g_thread1->running){
      bitmap_t *bitmap = bitmap_create_ex(800, 480, 3200, BITMAP_FMT_BGRA8888);
      helper_bitmap_resize(&bitmap, 400, 480);

      bitmap_destroy(bitmap);
      sleep_ms(16);
    }
    return NULL;
}

void *thread_func2(void *args){
    while(g_thread1->running){
      bitmap_t *bitmap = bitmap_create_ex(800, 480, 3200, BITMAP_FMT_BGRA8888);
      helper_bitmap_resize(&bitmap, 400, 480);

      bitmap_destroy(bitmap);
      sleep_ms(100);
    }
    return NULL;
}

/**
 * 初始化程序
 */
ret_t application_init(void) {
  custom_widgets_register();
  application_on_launch();

  if (strlen(APP_SYSTEM_BAR) > 0) {
    navigator_to(APP_SYSTEM_BAR);
  }

  if (strlen(APP_BOTTOM_SYSTEM_BAR) > 0) {
    navigator_to(APP_BOTTOM_SYSTEM_BAR);
  }

  g_thread1 = my_thread_create(thread_func1, NULL);
  my_thread_start(g_thread1);

  g_thread2 = my_thread_create(thread_func2, NULL);
  my_thread_start(g_thread2);

  return navigator_to(APP_START_PAGE);
}

/**
 * 退出程序
 */
ret_t application_exit(void) {
  my_thread_destroy(g_thread1); 
  my_thread_destroy(g_thread2);

  application_on_exit();
  log_debug("application_exit\n");

  return RET_OK;
}

输出:

sudo gdb ./bin/bitmap_resize_crash_repo 
[sudo] password for zhangdalin: 
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.2) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./bin/bitmap_resize_crash_repo...
(gdb) r
Starting program: /home/zhangdalin/AWStudioProjects/bitmap_resize_crash_repo/bin/bitmap_resize_crash_repo 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
app_root=./res
devices_load : path = file:///home/zhangdalin/AWStudioProjects/bitmap_resize_crash_repo/config/devices.json
devices[0]: path = /dev/fb0, type = fb
devices[1]: path = /dev/dri/card0, type = drm
fb_info_t: /dev/fb0
xres=800 yres=480
xres_virtual=1024 yres_virtual=768
bits_per_pixel=32 line_length=4704
fb_info_t: red(16 8) green(8 8) blue(0 8)
xpanstep=1 ywrapstep=0
fb_size=2257920 fb_total_size=4163040 fb_nr=1 smem_len=4163040
fb_open clear
fb_open ok
[Detaching after vfork from child process 690815]
run in vmware and fix FBIOPAN_DISPLAY block issue
=========fb_number=1
ratio=1.000000 800 480
ratio=1.000000 800 480
Build at: Dec 12 2024 19:07:14
[New Thread 0x7ffff7009700 (LWP 690829)]
[New Thread 0x7fffee808700 (LWP 690830)]
window home_page open
vgcanvas_asset_manager_remove_font:419 condition(vg_data != NULL) failed!
vgcanvas_asset_manager_remove_image:329 condition(vg_data != NULL) failed!

Thread 2 "bitmap_resize_c" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7009700 (LWP 690829)]
0x00007ffff7cc9126 in vgcanvas_asset_manager_vg_list_compare (a=0x0, b=0x7ffff0001070) at /home/zhangdalin/AWStudioProjects/awtk/src/base/vgcanvas_asset_manager.inc:174
174       if (vgcanvas_asset_vg->vg == (vgcanvas_t*)b) {
(gdb) bt
#0  0x00007ffff7cc9126 in vgcanvas_asset_manager_vg_list_compare (a=0x0, b=0x7ffff0001070) at /home/zhangdalin/AWStudioProjects/awtk/src/base/vgcanvas_asset_manager.inc:174
#1  0x00007ffff7cc9846 in vgcanvas_asset_manager_darray_find_index (darray=<optimized out>, compare=0x7ffff7cc9120 <vgcanvas_asset_manager_vg_list_compare>, data=0x7ffff0001070) at /home/zhangdalin/AWStudioProjects/awtk/src/base/vgcanvas_asset_manager.inc:190
#2  0x00007ffff7cca7f3 in vgcanvas_asset_manager_remove_font (vgcanvas_asset_manager=vgcanvas_asset_manager@entry=0x55555556eab0, vg=0x7ffff0001070, font_name=font_name@entry=0x0) at /home/zhangdalin/AWStudioProjects/awtk/src/base/vgcanvas_asset_manager.inc:418
#3  0x00007ffff7ccab15 in vgcanvas_asset_manager_remove_vg (vgcanvas_asset_manager=0x55555556eab0, vg=0x7ffff0001070) at /home/zhangdalin/AWStudioProjects/awtk/src/base/vgcanvas_asset_manager.inc:466
#4  0x00007ffff7d79e9e in vgcanvas_nanovg_soft_close_asset_manager (vg=0x7ffff0001070) at build/var/awtk/src/vgcanvas/vgcanvas_nanovg_soft.inc:240
#5  vgcanvas_nanovg_destroy (vgcanvas=0x7ffff0001070) at build/var/awtk/src/vgcanvas/vgcanvas_nanovg_soft.inc:247
#6  0x00007ffff7d724ea in lcd_mem_deinit (mem=0x7ffff0000d90) at /home/zhangdalin/AWStudioProjects/awtk/src/lcd/lcd_mem.h:91
#7  lcd_mem_destroy (lcd=0x7ffff0000d90) at /home/zhangdalin/AWStudioProjects/awtk/src/lcd/lcd_mem.inc:669
#8  0x00007ffff7cd88ca in canvas_offline_destroy (canvas=canvas@entry=0x7ffff0000c10) at build/var/awtk/src/base/canvas_offline.inc:584
#9  0x00005555555570e9 in helper_bitmap_resize (_bmp=_bmp@entry=0x7ffff7008ed0, new_height=480, new_width=400) at src/application.c:116
#10 0x00005555555571d7 in thread_func1 (args=<optimized out>) at src/application.c:125
#11 0x00007ffff7e1478a in entry (arg=<optimized out>) at build/var/awtk/src/platforms/pc/thread_with_pthread.c:411
#12 0x00007ffff77a9609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#13 0x00007ffff7ac5353 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

源项目输出:
a7075b7e496198335bc9da42958f300

@xianjimli
Copy link
Member

gui的函数一般都只能在GUI线程使用。

resize 图片可以参考这个实现:tools/image_resize/resize.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants