硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2498|回复: 11
收起左侧

[ThreadX全家桶] threadX gnu 版本如何安全的使用 C 库?

[复制链接]

2

主题

23

回帖

29

积分

新手上路

积分
29
发表于 2022-2-14 16:50:55 | 显示全部楼层 |阅读模式
本帖最后由 luguan1997 于 2022-2-14 17:06 编辑

我现在有很多线程要记录浮点数据,会用到sprintf转换到字符串的形式。网上看到不少讨论说 newlibc(arm-none-eabi-gcc 所采用的) 的 vsprintf 之类的函数,多线程使用浮点会有问题。
自己也尝试拿代码测试了一下,创建三个优先级不同,可以抢占的线程,每个线程都是执行一千次到一万次 sprintf 然后休眠几个 tick,很容易会导致异常。
单步调试常常会死在 _dtoa 或者 _Balloc 这些内部的函数里。
而如果给它们互斥锁上,就没有问题:#define TRYS 2000
void thread_test_entry(ULONG thread_input)
{
    int try;
    double a = 1.1111;
    char str[20];
    while (1)
    {
        tx_thread_sleep(2);

        try = TRYS;

        tx_mutex_get(&mutex333, TX_WAIT_FOREVER);
        while(try--)
            sprintf(str, "%lf\n", a);
        tx_mutex_put(&mutex333);
    }
}

看到一个解决办法是 Freertos的 newlib and FreeRTOS (nadler.com),但应该所有 RTOS 是互通的。
所以想问一下,使用 threadX 如何能安全使用 arm-none-eabi-gcc 编译器提供的库函数?有没有人做过好用的方案?

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115834
QQ
发表于 2022-2-14 17:08:14 | 显示全部楼层
其实这个牵扯到一个很重要的问题,效率。

比如我们仅仅是想简单的调用下sprintf,非常的不划算。

像MDK里面的C库是一个专门的封装层
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115834
QQ
发表于 2022-2-14 17:08:18 | 显示全部楼层
其实这个牵扯到一个很重要的问题,效率。

比如我们仅仅是想简单的调用下sprintf,非常的不划算。

像MDK里面的C库是一个专门的封装层
  1. #if ( !defined(RTX_NO_MULTITHREAD_CLIB) && \
  2.      ( defined(__CC_ARM) || \
  3.       (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))) && \
  4.       !defined(__MICROLIB))

  5. #define LIBSPACE_SIZE 96

  6. //lint -esym(714,__user_perthread_libspace,_mutex_*) "Referenced by C library"
  7. //lint -esym(765,__user_perthread_libspace,_mutex_*) "Global scope"
  8. //lint -esym(9003, os_libspace*) "variables 'os_libspace*' defined at module scope"

  9. // Memory for libspace
  10. static uint32_t os_libspace[OS_THREAD_LIBSPACE_NUM+1][LIBSPACE_SIZE/4] \
  11. __attribute__((section(".bss.os.libspace")));

  12. // Thread IDs for libspace
  13. static osThreadId_t os_libspace_id[OS_THREAD_LIBSPACE_NUM] \
  14. __attribute__((section(".bss.os.libspace")));

  15. // Check if Kernel has been started
  16. static uint32_t os_kernel_is_active (void) {
  17.   static uint8_t os_kernel_active = 0U;

  18.   if (os_kernel_active == 0U) {
  19.     if (osKernelGetState() > osKernelReady) {
  20.       os_kernel_active = 1U;
  21.     }
  22.   }
  23.   return (uint32_t)os_kernel_active;
  24. }

  25. // Provide libspace for current thread
  26. void *__user_perthread_libspace (void);
  27. void *__user_perthread_libspace (void) {
  28.   osThreadId_t id;
  29.   uint32_t     n;

  30.   if (os_kernel_is_active() != 0U) {
  31.     id = osThreadGetId();
  32.     for (n = 0U; n < (uint32_t)OS_THREAD_LIBSPACE_NUM; n++) {
  33.       if (os_libspace_id[n] == NULL) {
  34.         os_libspace_id[n] = id;
  35.       }
  36.       if (os_libspace_id[n] == id) {
  37.         break;
  38.       }
  39.     }
  40.     if (n == (uint32_t)OS_THREAD_LIBSPACE_NUM) {
  41.       (void)osRtxKernelErrorNotify(osRtxErrorClibSpace, id);
  42.     }
  43.   } else {
  44.     n = OS_THREAD_LIBSPACE_NUM;
  45.   }

  46.   //lint -e{9087} "cast between pointers to different object types"
  47.   return (void *)&os_libspace[n][0];
  48. }

  49. // Mutex identifier
  50. typedef void *mutex;

  51. //lint -save "Function prototypes defined in C library"
  52. //lint -e970 "Use of 'int' outside of a typedef"
  53. //lint -e818 "Pointer 'm' could be declared as pointing to const"

  54. // Initialize mutex
  55. __USED
  56. int _mutex_initialize(mutex *m);
  57. int _mutex_initialize(mutex *m) {
  58.   int result;

  59.   *m = osMutexNew(NULL);
  60.   if (*m != NULL) {
  61.     result = 1;
  62.   } else {
  63.     result = 0;
  64.     (void)osRtxKernelErrorNotify(osRtxErrorClibMutex, m);
  65.   }
  66.   return result;
  67. }

  68. // Acquire mutex
  69. __USED
  70. void _mutex_acquire(mutex *m);
  71. void _mutex_acquire(mutex *m) {
  72.   if (os_kernel_is_active() != 0U) {
  73.     (void)osMutexAcquire(*m, osWaitForever);
  74.   }
  75. }

  76. // Release mutex
  77. __USED
  78. void _mutex_release(mutex *m);
  79. void _mutex_release(mutex *m) {
  80.   if (os_kernel_is_active() != 0U) {
  81.     (void)osMutexRelease(*m);
  82.   }
  83. }

  84. // Free mutex
  85. __USED
  86. void _mutex_free(mutex *m);
  87. void _mutex_free(mutex *m) {
  88.   (void)osMutexDelete(*m);
  89. }
复制代码


回复

使用道具 举报

2

主题

23

回帖

29

积分

新手上路

积分
29
 楼主| 发表于 2022-2-14 17:28:30 | 显示全部楼层
eric2013 发表于 2022-2-14 17:08
其实这个牵扯到一个很重要的问题,效率。

比如我们仅仅是想简单的调用下sprintf,非常的不划算。

keil 的听说多线程是安全的,但公司不让用
arm-none-eabi-gcc 的就想问问有没有人做过类似的 wrap 层给 threadX
要不是最近网上看到,都没想过库函数会有这种安全问题
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115834
QQ
发表于 2022-2-15 09:52:30 | 显示全部楼层
luguan1997 发表于 2022-2-14 17:28
keil 的听说多线程是安全的,但公司不让用
arm-none-eabi-gcc 的就想问问有没有人做过类似的 wrap 层给  ...

IAR也有这个封装层。对应文件在iar的安装目录里面。

GCC的话,如果是embedded studio的话,好像也有,
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115834
QQ
发表于 2022-2-15 09:52:37 | 显示全部楼层
luguan1997 发表于 2022-2-14 17:28
keil 的听说多线程是安全的,但公司不让用
arm-none-eabi-gcc 的就想问问有没有人做过类似的 wrap 层给  ...

IAR也有这个封装层。对应文件在iar的安装目录里面。

GCC的话,如果是embedded studio的话,好像也有,
回复

使用道具 举报

0

主题

275

回帖

275

积分

高级会员

积分
275
发表于 2022-2-15 10:58:49 | 显示全部楼层
后来C库增加了snprintf,snprintf_s等之类的函数, 你试试这两个
回复

使用道具 举报

3

主题

424

回帖

433

积分

高级会员

积分
433
发表于 2022-2-15 11:09:45 | 显示全部楼层
看newlib文档吧,里面也有讲解,关键字:桩函数。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115834
QQ
发表于 2022-2-15 11:16:55 | 显示全部楼层
regbbs 发表于 2022-2-15 10:58
后来C库增加了snprintf,snprintf_s等之类的函数, 你试试这两个

可以,就是限制个数,不太方便。
回复

使用道具 举报

0

主题

2

回帖

2

积分

新手上路

积分
2
发表于 2022-2-15 23:58:23 | 显示全部楼层
printf,sprintf都是不可重入函数吧,不是线程安全的
回复

使用道具 举报

5

主题

197

回帖

212

积分

高级会员

积分
212
发表于 2022-2-16 00:30:19 | 显示全部楼层
楼上回答都挺好,首先这俩函数本来就不是可重入的,其次可以通过实现桩函数(__malloc_lock(), __malloc_unlock() stubs)往newlib里插桩加上互斥锁,最后newlib的源码其实很好集成进工程,构建选项里加上重入开关直接编译就好了

附件这篇文档感觉比较符合主题,希望能帮到你。

Porting and Using Newlib in Embedded Systems.pdf

154.33 KB, 下载次数: 24

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-5-22 05:54 , Processed in 0.330726 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表