主要内容

编写线程安全的s -函数的指南

金宝app®允许您在多线程编程中并行运行s函数,这使得模拟运行比串行运行更快。使用S-functions进行多线程编程要求您使S-functions线程安全。创建线程安全代码需要确保多个线程之间共享的数据得到保护,以便数据和结果符合预期。使用非线程安全的s函数进行模拟可能会导致意外行为。

背景

C/ c++ s -函数是用C或c++实现的,并内置到称为MEX文件的共享库中。当一个s函数块引用一个共享库时,MATLAB®将s函数块加载到进程中。当多个S-function块引用同一个共享库时,它们也引用初始共享库副本。这个过程导致多个s函数块共享共享库拥有的相同数据。因此,多线程的s函数块可以同时访问相同的数据。

此外,如果这些S-function引用相同的资源,那么多线程的S-function块可以同时访问相同的资源(例如文件),即使这些S-function块与不同的S-function相关联。

的指导方针

当s函数可以使用多个线程安全地并发执行时,它通常被认为是线程安全的。要将s函数指定为线程安全的,请使用ssSetRuntimeThreadSafetyCompliance函数。如果您不确定s函数的线程安全,请使用以下指导原则来研究并使其线程安全。

数据共享

定义 问题 解决方案

s -函数使用指针(例如,ssSetUserDatassGetUserDatassSetPWorkValuessGetPWorkValue).s函数很容易使用这些指针共享数据。

多个线程可以使用指针访问相同的数据。如果线程试图在同一时间写入相同的内存位置,就会违反线程安全。多线程的并发读是安全的,只要在读之前、读期间和读之后没有写操作,这可能会导致不一致的缓存。

在访问多线程共享的数据时要小心。

  • 如果数据是只读的,则将其设置为常量。

  • 要控制对数据的访问,可以考虑使用互斥对象。互斥锁还可以确保缓存的一致性。

全局变量

定义 问题 解决方案

全局变量是在整个应用程序中可访问的共享数据。

多线程写入不受保护的共享数据是不安全的。只要在读取之前、期间和之后没有写操作,那么读取就是安全的,而这可能会导致不一致的缓存。

  • 如果要写入全局数据,请本地化它,使用互斥锁控制对它的访问,或更改算法的语义。为了确保缓存一致性,还可以考虑使用原子或互斥锁之类的内存栅栏。

  • 如果您正在阅读,请将全局变量设置为常量。

局部静态变量初始化

定义 问题 解决方案

局部静态变量存储在一个位置。

  • 在c++中,局部静态变量是在进入函数作用域时初始化的,不是线程安全的。

  • 在C语言中,只要赋值右边的值(被赋给变量的值)是编译时常量,局部静态变量就会在应用程序开始时初始化。这些变量是线程安全的。

如果多个线程同时进入功能范围,则软件会多次尝试写入同一个位置。即使局部静态变量是常量,这个问题仍然存在。

  • 如果您正在使用c++ 11之前的c++版本,使用互斥或线程安全的初始化机制来保护局部静态变量的初始化,例如std:: call_onceboost:: call_once

  • 如果您正在使用c++ 11或更高版本,则局部静态变量初始化保证是线程安全的。

资源

定义 问题 解决方案

资源是显式地向系统请求并返回给系统的实体。一些资源示例包括动态分配的内存、文件、数据库连接和网络套接字。您的应用程序可能需要管理资源。

从多个线程访问资源可能不是线程安全的,比如从多个线程读写文件。即使这些操作是线程安全的,它们也可能不会产生预期的结果。

管理资源时要谨慎。资源的线程安全取决于它的实现。有关线程安全规范的更多信息,请参阅资源文档。还可以使用互斥锁之类的机制来保护对资源的访问。

可重入性

定义 问题 解决方案

如果从同一个线程(递归地)调用多次是安全的,则函数是可重入的。例如,strtok函数是不可重入的,因为它保留了要令牌化的字符串的某些内部状态。如果一个函数没有调用不可重入的函数,那么它就是可重入的。

从多个线程调用不可重入函数可能不安全。

使函数可重入。例如:

  • 消除函数持有的状态。

  • 用可重入等价物替换不可重入函数调用。例如,替换strtokstrtok_r

mexCallMATLAB

定义 问题 解决方案

s函数可以调用MATLAB使用mexCallMATLAB函数。

金宝appSimulink代码处理mexCallMATLAB功能不是线程安全的。

不叫mexCallMATLAB你的功能。

除了免费代码

定义 问题 解决方案

只要在调用s函数时,它的所有子例程都不存在跳远的可能性,那么s函数就是没有异常的。有关无异常s函数的更多信息,请参见除了免费代码

当s函数不是无异常时,它的子例程会被间接调用mexCallMATLAB,它不是线程安全的(参见mexCallMATLAB).

检查你的s函数是否有跳远。如果没有异常,则使用SS_OPTION_EXCEPTION_FREE_CODE ssSetOptions(年代)函数。如果s函数不顾此标志进行长跳跃,则会发生不可预测的行为。

如果s -函数抛出异常,但使用try/catch块来捕获异常,则该s -函数是安全的。

数据竞赛

定义 问题 解决方案

当应用程序的输出依赖于执行顺序时,即应用程序的行为在执行之间发生变化,就会发生数据竞争。

应用程序可能有意外的行为。

考虑以下其中之一:

  • 修改算法以消除数据竞争。

  • 使用锁来控制代码关键部分的执行顺序,或者使关键操作成为原子操作。

挥发性

定义 问题 解决方案

挥发性关键字告诉编译器不要优化变量,因为它的值可能会被编译器不知道的某些机制更改。

应用程序可能错误地使用挥发性实现线程安全。挥发性不提供线程间的原子性或同步性。

请勿使用挥发性线程安全的关键字。

错误状态

定义 问题 解决方案

S-functions使用ssSetErrorStatusssGetErrorStatusssSetLocalErrorStatus,ssGetLocalErrorStatus访问错误状态。

ssSetErrorStatusssGetErrorStatus不是线程安全的。这些函数可以覆盖现有错误并导致报告不准确的错误。例如,块A可能报告块B抛出的错误。

使用线程安全的ssSetLocalErrorStatus,ssGetLocalErrorStatus功能。不要使用ssSetErrorStatusssGetErrorStatus

另请参阅

|

相关的话题