可重入函数及函数编写规范

合集下载

一、可重入函数

一、可重入函数
即:要么是调用者和被调用者对参数均不作合法性检查
结果就遗漏了合法性检查这一必要的处理过程
造成问题隐患;要么就是调用者和被调用者均对参数进行合法性检查
这种情况虽不会造成问题
但产生了冗余代码
降低了效率
6 :防止将函数的参数作为工作变量
说明:将函数的参数作为工作变量
有可能错误地改变参数内容
则必须是STATIC的局部变量的地址作为返回值
若为AUTO类
则返回为错针
示例:如下函数
其返回值(即功能)是不可预测的
unsigned int integer_sum( unsigned int base )
{
unsigned int index;
static unsigned int sum = 0; // 注意
如果必须访问全局变量
记住利用互斥信号量来保护全局变量
绝不调用任何不可重入函数
3)不可重入函数:
函数中使用了静态变量
无论是全局静态变量还是局部静态变量
函数返回静态变量
函数中调用了不可重入函数
函数体内使用了静态的数据结构;
函数体内调用了malloc()或者free()函数;
{
unsigned int count ;
int sum_temp;
sum_temp = 0;
for (count = 0; count < num; count ++)
{
sum_temp += data[count];
19 :避免使用无意义或含义不清的动词为函数命名
说明:避免用含义不清的动词如process、handle等为函数命名

单片机程序实现可重入和不可重入函数方法

单片机程序实现可重入和不可重入函数方法

单片机程序实现可重入和不可重入函数方法
可重入函数是指一个函数可以被多个任务同时调用而不会产生冲突的函数,不可重入函数是指一个函数在被同时调用时可能会产生冲突的函数。

实现可重入函数的方法如下:1. 避免使用全局变量和静态变量。

全局变量和静态变量可能会在函数调用期间被修改,导致并发访问时出现冲突。

如果需要使用全局变量,可以使用互斥锁保护对全局变量的访问。

2. 使用局部变量。

局部变量是每次函数调用时创建的,不会被其他任务访问到,因此可以保证并发访问的安全性。

3. 使用栈上的变量。

栈上的变量是每次函数调用时分配的,不会被其他任务访问到,因此可以保证并发访问的安全性。

4. 避免使用非可重入函数。

如果需要使用非可重入函数,可以使用互斥锁保护对非可重入函数的访问。

实现不可重入函数的方法如下:1. 使用全局变量和静态变量。

全局变量和静态变量是多个任务共享的,如果在函数中使用全局变量和静态变量,可能会导致并发访问时出现冲突。

2. 使用非线程安全的库函数。

一些库函数在多任务环境下可能不是线程安全的,如果在函数中使用这些库函数,可能会导致并发访问时出现冲突。

3. 使用非原子操作的指令。

一些指令在执行时可能是非原子的,如果在函数中使用这些指令,可能会导致并发访问时出现冲突。

需要注意的是,可重入函数不一定是线程安全的,因为线程安全还需要考虑共享资源的访问和同步。

而不可重入函数通常也不是线程安全的,因为它可能会对全局资源进行修改,需要使用互斥锁或其他同步
机制来保护对全局资源的访问。

linux中信号处理函数为可重入函数

linux中信号处理函数为可重入函数

在Linux 中,信号处理函数应该尽量设计为可重入函数。

可重入函数是指能够在多个线程同时调用时保持其行为正确的函数,无论这些线程是同一进程内的还是不同进程内的。

以下是一些编写可重入信号处理函数的指导原则:
1. 避免使用非可重入函数:在信号处理函数中尽量避免使用非可重入的函数,因为这些函数可能会使用全局变量或静态变量,如果多个信号处理函数同时调用它们,可能会导致数据竞争和意外的结果。

2. 使用信号安全的函数:在信号处理函数中只使用被认为是“信号安全”的函数。

信号安全的函数是指在信号处理函数中能够正常工作且不会破坏全局状态的函数。

例如,可以使用`write()` 函数来输出消息,但不可使用`printf()` 函数。

3. 如果必须使用非可重入函数:如果必须在信号处理函数中使用非可重入函数,确保使用保护措施来防止数据竞争。

例如,可以使用互斥锁来保护全局变量的读写操作,以避免多个信号处理函数之间的竞争条件。

4. 确保正确设置信号处理函数:在设置信号处理函数时,使用`sigaction()` 函数而不是`signal()` 函数。

`sigaction()` 函数提供了更精确的信号处理控制,可以指定信号处理函数的选项和属性。

通过遵循这些原则,可以编写出更安全和可靠的可重入信号处理函数,从而提高应用程序在处理信号时的稳定性和可维护性。

可重入函数

可重入函数

占先式(Preemptive)
低优先级任务 中断服务程序使 高优先级任务就绪
(1)
(2)
ISR
(5)
(3)
高优先级任务
TIME
(4)
(6)
高优先级任务得到 CPU使用权
可重入型函数
可以被一个以上的任务调用,而不必担心数据的破坏。可重 入型函数任何时候都可以被中断,一段时间以后又可以运行,而相 应数据不会丢失。可重入型函数只使用局部变量,即变量保存在 CPU寄存器中或堆栈中。 一个不可重入型函数的例子
什么是可重入代码
• 可重入的代码指的是一段代码(比 如:一个函数)可以被多个任务同 时调用,而不必担心会破坏数据。
• 也就是说,可重入型函数在任何时 候都可以被中断执行,过一段时间 以后又可以继续运行,而不会因为 在函数中断的时候被其他的任务重 新调用,影响函数中的数据。
可重入代码举例
程序1:可重入型函数 void swap(int *x, int *y) { int temp; temp=*x; *x=*y; *y=temp; }
占先式(preemptive)
当系统响应时间很重要时,要使用占先式 (preemptive)内核。最高优先级的任务一旦 就绪,总能得到CPU的控制权。 当一个运行着的任务使一个比它优先级高 的任务进入了就绪态,当前任务的CPU使用权 就被剥夺了,或者说被挂起了,那个高优先级 的任务立刻得到了CPU的控制权。 使用占先式内核时,应用程序不应直接使 用不可重入型函数。如果调入不可重入型函数 时,低优先级的任务CPU的使用权被高优先级 任务剥夺,不可重入型函数中的数据有可能被 破坏。
非可重入代码举例
程序2:非可重入型函数 int temp; void swap(int *x, int *y) { temp=*x; *x=*y; *y=temp; 返回 }

C_C++编程规范-华为标准-精

C_C++编程规范-华为标准-精
值范围及公共变量间的关系。 5-3:明确公共变量与操作此公共变量的函数或过
程的关系,如访问、修改及创建等。 5-4:当向公共变量传递数据时,要十分小心,防
止赋与不合理的值或越界等现象发生。 5-5:防止局部变量与公共变量同名。 5-6:严禁使用未经初始化的变量作为右值。
编程规范详解——函数、过程 处理。
1-11:在两个以上的关键字、变量、常量进行对等操作时,它们之间 的操作符之前、之后或者前后要加空格;进行非对等操作时,如果 是关系密切的立即操作符(如->),后不应加空格。
1-12: 程序结构清析,简单易懂,单个函数的程序行数不得超过100行。
编程规范详解——注释
2-1:一般情况下,源程序有效注释量必须在20%以上。 2-2:说明性文件(如头文件.h文件、.inc文件、.def文件、编译说明文件.cfg
编程规范详解——注释
2-9:对于所有有物理含义的变量、常量,如果其命名不是充分自注释的,在 声明时都必须加以注释,说明其物理含义。变量、常量、宏的注释应放在 其上方相邻位置或右方。
2-10:数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自 注释的,必须加以注释。对数据结构的注释应放在其上方相邻位置,不可 放在下面;对结构中的每个域的注释放在此域的右方。
后进入下一个case处理,必须在该case语句处理完、下一个case语句前加 上明确的注释。
编程规范详解——标识符的命名
3-1:标识符的命名要清晰、明了,有明确含义,同时使用完 整的单词或大家基本可以理解的缩写,避免使人产生误解。
3-2:命名中若使用特殊约定或缩写,则要有注释说明 3-3:自己特有的命名风格,要自始至终保持一致,不可来回
延用华为标准
C/C++编程规范

可重入函数和不可重入函数

可重入函数和不可重入函数

可重入函数和不可重入函数
可重入函数和不可重入函数是计算机编程中重要的概念,它们通常用于多线程编程。

可重入函数是指在多线程环境下可以安全地被多个线程同时调用,而不会出现不同线程之间的相互干扰或冲突。

不可重入函数则相反,不能被多个线程同时调用,因为会出现不同线程之间的相互干扰或冲突。

可重入函数通常具有以下特点:不使用或共享全局变量;不使用或共享静态变量;不使用或共享动态内存分配的内存;不使用或共享文件或设备等共享资源。

这些特点使得可重入函数可以被多个线程同时调用,而不会出现不同线程之间的相互干扰或冲突。

不可重入函数通常具有以下特点:使用或共享全局变量;使用或共享静态变量;使用或共享动态内存分配的内存;使用或共享文件或设备等共享资源。

这些特点使得不可重入函数不能被多个线程同时调用,因为会出现不同线程之间的相互干扰或冲突。

在多线程编程中,使用可重入函数可以更好地保证程序的正确性和稳定性。

因为多个线程同时调用可重入函数不会出现冲突,从而避免了程序崩溃或数据损坏
等问题。

而使用不可重入函数则需要进行同步操作,以避免不同线程之间的相互干扰或冲突。

总之,可重入函数和不可重入函数是多线程编程中非常重要的概念。

了解它们的特点和使用方式可以更好地提高程序的正确性和稳定性,从而保证程序的质量
和性能。

c++函数重载规则

c++函数重载规则

c++函数重载规则
C++中的函数重载是指在同一个作用域内定义多个同名函数,但是它们的形参个数或类型不同。

函数重载使得程序员可以用同一个函数名来完成不同的操作,提高了代码的可读性和复用性。

函数重载的规则如下:
1.函数名称相同:重载函数的名称必须相同。

2.形参个数不同:重载函数的形参个数必须不同。

例如,可以定义一个带一个参数的函数和一个带两个参数的函数。

3.形参类型不同:重载函数的形参类型必须不同。

例如,可以定义一个带整型参数的函数和一个带浮点型参数的函数。

4.形参顺序不同:重载函数的形参顺序必须不同。

例如,可以定义一个带两个整型参数的函数和一个带一个整型参数和一个浮点型参数的函数。

5.返回值类型不同:重载函数的返回值类型可以不同,但不能仅仅是返回值类型不同。

例如,不能定义一个返回整型的函数和一个返回浮点型的函数,它们的形参和形参类型都必须不同。

需要注意的是,函数重载并非只有形参不同,例如下面的代码就不是函数重载:
int add(int a, int b) {
return a + b;
}
double add(int a, int b) {
return a + b + 0.5;
}
因为这两个函数的形参类型相同,不能被视为函数重载。

总之,函数重载是C++中非常重要的特性,它允许我们定义多个同名函数,并根据参数类型和个数自动选择合适的函数进行调用。

在编写C++程序时,我们应该充分利用函数重载,从而提高代码的可读性和可维护性。

可重入函数的概念

可重入函数的概念

可重入函数的概念主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。

也可以这样理解,重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰。

如果确实需要访问全局变量(包括static),一定要注意实施互斥手段。

可重入函数在并行运行环境中非常重要,但是一般要为访问全局变量付出一些性能代价。

编写可重入函数时,若使用全局变量,则应通过关中断、信号量(即P、V操作)等手段对其加以保护。

说明:若对所使用的全局变量不加以保护,则此函数就不具有可重入性,即当多个进程调用此函数时,很有可能使有关全局变量变为不可知状态。

示例:假设Exam是int型全局变量,函数Squre_Exam返回Exam平方值。

那么如下函数不具有可重入性。

unsigned int example( int para ) {unsigned int temp;Exam = para; // (**)temp = Square_Exam( );return temp;}此函数若被多个进程调用的话,其结果可能是未知的,因为当(**)语句刚执行完后,另外一个使用本函数的进程可能正好被激活,那么当新激活的进程执行到此函数时,将使Exam赋与另一个不同的para值,所以当控制重新回到“temp = Square_Exam( )”后,计算出的temp很可能不是预想中的结果。

此函数应如下改进。

unsigned int example( int para ) {unsigned int temp;[申请信号量操作] //(1)Exam = para;temp = Square_Exam( );[释放信号量操作]return temp;}(1)若申请不到“信号量”,说明另外的进程正处于给Exam赋值并计算其平方过程中(即正在使用此信号),本进程必须等待其释放信号后,才可继续执行。

Linux中可重入函数与不可重入函数详解

Linux中可重入函数与不可重入函数详解

Linux中可重⼊函数与不可重⼊函数详解
Linux 中可重⼊函数与不可重⼊函数详解
可重⼊函数和不可重⼊函数说起来有点拗⼝,其实写过多进程(线程)程序的⼈肯定很快就能明⽩这两种函数是个神马东西。

下⾯是我对这两个函数的理解:
可重⼊函数可以理解为是能被中断的函数,并且它被中断返回后也不会出现什么错误。

不可重⼊函数可以理解为如果函数被中断的话,就会出现不可预料的错误。

这是因为函数中使⽤了⼀些系统资源,⽐如全局变量区,中断向量表之类的。

⽐如多个进程同时对⼀个⽂件进⾏写操作,如果没有同步机制的话,对⽂件的写⼊就会变得难以控制。

在多进程(线程)环境中⼀定要考虑到函数的可重⼊性。

例如下⾯的例⼦:
int sum( int count)
{
static int sum = 0;
int i = 0;
for (i= 1; index <= count; i++)
sum += i;
return sum;
}
这段代码中使⽤了static关键字,如果多个进程同时执⾏这⼀段代码的话就会出现不可预测的结果。

在可重⼊函数中,⼀定要避免使⽤static变量。

或者需要使⽤⼀定的同步原则才可以。

要想将上⾯的代码改为可重⼊函数,只要将static变量改为⾮static的变量就可以了。

在编写可重⼊函数时,如果函数中使⽤到了全局变量,则应通过关中断、信号量(即P、V操作)等⼿段对其加以保护,在函数体中尽量使⽤局部变量。

感谢阅读,希望能帮助到⼤家,谢谢⼤家对本站的⽀持!。

函数可重入性及编写规范2

函数可重入性及编写规范2

函数可重入性及编写规范(2)[作者:佚名转贴自:网络点击数:360 更新时间:2007-1-23 文章录入:huitong ]上接函数可重入性及编写规范112 :尽量不要编写依赖于其他函数内部实现的函数说明:此条为函数独立性的基本要求。

由于目前大部分高级语言都是结构化的,所以通过具体语言的语法要求与编译器功能,基本就可以防止这种情况发生。

但在汇编语言中,由于其灵活性,很可能使函数出现这种情况。

示例:如下是在DOS下TASM的汇编程序例子。

过程Print_Msg的实现依赖于Input_Msg的具体实现,这种程序是非结构化的,难以维护、修改。

... // 程序代码proc Print_Msg // 过程(函数)Print_Msg... // 程序代码jmp LABEL... // 程序代码endpproc Input_Msg // 过程(函数)Input_Msg... // 程序代码LABEL:... // 程序代码endp13 :避免设计多参数函数,不使用的参数从接口中去掉说明:目的减少函数间接口的复杂度。

14 :非调度函数应减少或防止控制参数,尽量只使用数据参数说明:本建议目的是防止函数间的控制耦合。

调度函数是指根据输入的消息类型或控制命令,来启动相应的功能实体(即函数或过程),而本身并不完成具体功能。

控制参数是指改变函数功能行为的参数,即函数要根据此参数来决定具体怎样工作。

非调度函数的控制参数增加了函数间的控制耦合,很可能使函数间的耦合度增大,并使函数的功能不唯一。

示例:如下函数构造不太合理。

int add_sub( int a, int b, unsigned char add_sub_flg ){if (add_sub_flg == INTEGER_ADD){return (a + b);}else{return (a b);}}不如分为如下两个函数清晰。

int add( int a, int b ){return (a + b);}int sub( int a, int b ){return (a b);}15 :检查函数所有参数输入的有效性16 :检查函数所有非参数输入的有效性,如数据文件、公共变量等说明:函数的输入主要有两种:一种是参数输入;另一种是全局变量、数据文件的输入,即非参数输入。

可重入函数的特点

可重入函数的特点

可重入函数的特点及其定义可重入函数是指在多线程环境下,函数可以被多个线程同时调用而不会引起不确定的结果。

它具有以下几个特点:1.线程安全:可重入函数在多线程环境下可以安全地被多个线程同时调用,不会出现数据竞争和不确定的结果。

2.可嵌套调用:可重入函数可以在自身的执行过程中再次调用自身,而不会出现死锁或其他问题。

3.无副作用:可重入函数不会对全局变量或静态变量进行修改,也不会引入全局状态,保证了函数的独立性和可重复使用性。

可重入函数的定义通常有以下几个要求:1.函数内部不使用全局变量:为了保证函数的可重入性,函数内部不应该依赖于全局变量或静态变量,而应该将所有需要的数据作为参数传入函数。

2.不修改静态变量:静态变量在函数调用过程中会被多个线程共享,如果可重入函数修改了静态变量,就会导致不确定的结果。

3.使用局部变量或栈上内存:为了避免线程间的数据竞争,可重入函数应该使用局部变量或栈上内存来保存临时数据。

4.使用信号量或互斥锁:为了保证多个线程之间的同步与互斥,可重入函数可以使用信号量或互斥锁来保护临界区。

可重入函数的用途可重入函数在多线程编程中具有重要的作用,它可以保证多个线程同时调用函数时不会出现竞争条件或数据不一致的问题。

下面是几个可重入函数的常见用途:1.管理共享资源:在多线程环境下,多个线程可能会同时访问共享资源,如内存、文件等。

可重入函数可以用来管理共享资源的访问,保证每个线程能够正确地访问资源而不会引起冲突。

2.实现线程安全的数据结构:可重入函数可以用来实现线程安全的数据结构,如队列、栈、链表等。

多个线程可以同时对数据结构进行操作,而不会导致数据结构的破坏或不一致。

3.处理信号:在多线程程序中,信号的处理通常是一个复杂的问题。

可重入函数可以用来处理信号,保证在信号处理函数中不会引起竞争条件或不确定的结果。

4.实现线程安全的库函数:可重入函数可以用来实现线程安全的库函数,使得库函数可以在多线程环境下被安全地调用。

C语言编码规范

C语言编码规范
9-6:过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭。
9-7:防止内存操作越界。
9-8:认真处理程序所能遇到的各种出错情况。
9-9:系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。
9-10:系统运行之初,要对加载到系统中的数据进行一致性检查。
2-8:注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。
2-9:对于所有有物理含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其物理含义。变量、常量、宏的注释应放在其上方相邻位置或右方。
作者Email地址:xianggu@
2-10:数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释的,必须加以注释。对数据结构的注释应放在其上方相邻位置,不可放在下面;对结构中的每个域的注释放在此域的右方。
2-11:全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等的说明。
2-12:注释与所描述内容进行同样的缩排。
1-4:循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首。
1-5:若函数或过程中的参数较长,则要进行适当的划分。
1-6:不允许把多个短语句写在一行中,即一行只写一条语句。
1-7:if、while、for、default、do等语句自占一行。
7-3:编程的同时要为单元测试选择恰当的测试点,并仔细构造测试代码、测试用例,同时给出明确的注释说明。测试代码部分应作为(模块中的)一个子模块,以方便测试代码在模块中的安装与拆卸(通过调测开关)。

CC++之什么是可重入函数和不可重入函数

CC++之什么是可重入函数和不可重入函数

CC++之什么是可重⼊函数和不可重⼊函数可重⼊函数在实时系统的设计中,经常会出现多个任务调⽤同⼀个函数的情况。

如果这个函数不幸被设计成为不可重⼊的函数的话,那么不同任务调⽤这个函数时可能修改其他任务调⽤这个函数的数据,从⽽导致不可预料的后果。

那么什么是可重⼊函数呢?所谓可重⼊是指⼀个可以被多个任务调⽤的过程,任务在调⽤时不必担⼼数据是否会出错。

不可重⼊函数在实时系统设计中被视为不安全函数。

满⾜下列条件的函数多数是不可重⼊的:(1)函数体内使⽤了静态的数据结构;(2)函数体内调⽤了malloc()或者free()函数;(3)函数体内调⽤了标准I/O函数。

如何写出可重⼊的函数?在函数体内不访问那些全局变量,不使⽤静态局部变量,坚持只使⽤缺省态(auto)局部变量,写出的函数就将是可重⼊的。

如果必须访问全局变量,记住利⽤互斥信号量来保护全局变量。

或者调⽤该函数前关中断,调⽤后再开中断。

可重⼊函数可以被⼀个以上的任务调⽤,⽽不必担⼼数据被破坏。

可重⼊函数任何时候都可以被中断,⼀段时间以后⼜可以运⾏,⽽相应的数据不会丢失。

可重⼊函数或者只使⽤局部变量,即保存在CPU寄存器中或堆栈中;或者使⽤全局变量,则要对全局变量予以保护。

说法2:⼀个可重⼊的函数简单来说,就是:可以被中断的函数。

就是说,你可以在这个函数执⾏的任何时候中断他的运⾏,在任务调度下去执⾏另外⼀段代码⽽不会出现什么错误。

⽽不可重⼊的函数由于使⽤了⼀些系统资源,⽐如全局变量区,中断向量表等等,所以他如果被中断的话,可能出现问题,所以这类函数是不能运⾏在多任务环境下的。

基本上下⾯的函数是不可重⼊的(1)函数体内使⽤了静态的数据结构;(2)函数体内调⽤了malloc()或者free()函数;(3)函数体内调⽤了标准I/O函数。

把⼀个不可重⼊函数变成可重⼊的唯⼀⽅法是⽤可重⼊规则来重写他。

其实很简单,只要遵守了⼏条很容易理解的规则,那么写出来的函数就是可重⼊的。

可重入函数

可重入函数

可重入函数
可重入函数是指:
1、它允许一个函数在已经开始其执行的情况下,再次被其本身调用。

2、把可重入函数等价于递归函数,它们都允许在函数体内通过调用它本身来实现循环。

不同的是,可重入函数的递归调用可以用多种可重入方式交叉进行,而不必等待前一调用结束后再开始新的调用。

3、可重入函数可提高程序实现的灵活性,不必额外定义变量来实现循环,而是在函数内部调用整个函数自身,它也可以实现多种重叠功能。

4、可重入函数可用于提供多种重叠性质编程,例如大量的并发任务处理、fork/join模式或服务器/客户端系统。

5、可重入函数可以更加复杂的编写,可以实现更复杂的类似位运算的实现,也可以通过可重入函数来处理复杂的控制,包括以树形结构实现的控制。

6、此外,可重入函数还可用于实现逐步累加,这样在编译器优化时可以提高运行效率,这也是和普通循环不同的地方。

7、可重入函数的另一个优点是它可以使程序更加稳定,因为也可以用它来进行错误控制,一旦出现错误,则能直接把调用过程重复执行,从而实现异常情况的处理。

最后,可重入函数还可以大大减少函数的代码量,并且使代码可重用性更强,使得程序更小巧、代码更加紧凑,更容易理解和维护。

对setcurrentcelladdresscore函数的可重入调用

对setcurrentcelladdresscore函数的可重入调用

对setcurrentcelladdresscore函数的可重入调用在多线程编程中,函数的可重入性是一个重要的概念。

可重入函数是指可以被多个线程同时调用的函数,而不会影响程序的正确性。

setcurrentcelladdresscore函数是一种常见的可重入函数,用于设置当前单元格的地址评分。

一、函数概述setcurrentcelladdresscore函数用于为一个单元格设置地址评分。

该函数通常接受一个单元格地址和评分值作为参数,并将评分值存储在相应的单元格中。

由于该函数可以被多个线程同时调用,因此它是可重入的。

二、可重入性特点可重入函数具有以下特点:1. 函数不会被修改,因此在多线程环境中不会出现冲突。

2. 函数可以多次调用,即具有重入性。

3. 函数的局部变量和参数是私有的,不会被其他线程访问或修改。

setcurrentcelladdresscore函数符合这些特点,因为它不会修改自身的代码或数据,并且局部变量和参数是私有的,不会被其他线程访问或修改。

三、调用方式1. 直接调用:可以在任何需要设置单元格地址评分的线程中直接调用该函数。

2. 线程安全调用:可以使用线程安全的函数调用库或机制来调用该函数,以确保多个线程同时调用时不会出现冲突。

3. 传递锁:可以在调用setcurrentcelladdresscore函数之前,传递一个锁对象作为参数,以确保在调用期间只有一个线程能够访问该函数。

无论采用哪种方式,都需要确保setcurrentcelladdresscore函数的调用是线程安全的,以避免出现竞态条件或其他并发问题。

四、注意事项在可重入调用的过程中,需要注意以下几点:1. 确保局部变量和参数的正确性:setcurrentcelladdresscore 函数的局部变量和参数应该是私有的,并且在使用前已经正确初始化。

2. 避免对共享资源的访问:如果存在共享资源,需要确保在多线程环境中对这些资源进行适当的同步和保护。

C语言编程规范

C语言编程规范

编码规范1. 头文件编码规范 (2)2. 函数编写规范 (2)3. 标识符命名与定义 (2)3.1通用命名规则 (2)3.2 变量命名规则 (3)3.3函数命名规则 (3)3.4 宏的命名规则 (3)4. 变量 (3)5. 宏、常量 (4)6. 质量保证 (4)7. 程序效率 (5)8. 注释 (5)9. 排版与格式 (6)10. 表达式 (7)11. 代码编辑、编译 (7)12. 安全性 (7)13. 可读性 (7)14. 可测性 (7)15. 单元测试 (8)16. 可移植性 (8)1. 头文件编码规范1. 禁止头文件循环依赖。

2. .c/.h文件不要包含用不到的头文件。

3. 禁止在头文件中定义变量。

4. 同一产品统一包含头文件排列方式。

(如功能块排序、文件名升序、稳定度排序。

)5. 只能通过包含头文件的方式使用其他.c提供的接口,禁止在.c中通过extern的方式使用外部函数接口、变量。

2. 函数编写规范1. 一个函数仅完成一件功能。

2. 重复代码应该尽可能提炼成函数。

3.为简单功能编写函数4.函数的返回值要清楚、明了,让使用者不容易忽视错误情况。

5. 避免函数过长,新增函数不超过100行(非空非注释行)。

6. 避免函数的代码块嵌套过深,新增函数的代码块嵌套不超过4层。

7. 可重入函数应避免使用全局变量和禁止使用static变量。

8. 设计高扇入,合理扇出(小于7)的函数。

9. 废弃代码(没有被调用的函数和变量)要及时注释(有助于更好理解程序)。

10. 对所调用函数的错误返回码要仔细、全面地处理。

11. 函数不变参数使用const。

12. 函数应避免使用全局变量、静态局部变量和I/O操作,不可避免的地方应集中使用。

13. 函数的参数个数不超过5个。

14. 减少或禁止函数本身或函数间的递归调用3. 标识符命名与定义3.1通用命名规则1. 标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。

单片机程序实现可重入和不可重入函数方法

单片机程序实现可重入和不可重入函数方法

单片机程序实现可重入和不可重入函数方法(最新版3篇)篇1 目录一、单片机程序实现可重入和不可重入函数方法的概述1.可重入函数和不可重入函数的概念2.单片机程序实现可重入和不可重入函数方法的意义3.实现可重入和不可重入函数方法的常用方法二、单片机程序实现可重入函数的详细步骤1.函数的可重入性设计原则2.函数参数的传递方式3.函数内部的变量定义和使用4.函数调用时的上下文切换和保存5.函数的返回值和异常处理三、单片机程序实现不可重入函数的详细步骤1.函数的不可重入性设计原则2.函数参数的传递方式3.函数内部的变量定义和使用4.函数调用时的上下文切换和保存5.函数的返回值和异常处理篇1正文一、单片机程序实现可重入和不可重入函数方法的概述1.可重入函数和不可重入函数的概念:可重入函数是指在多线程或多任务环境下,可以被多次调用的函数;不可重入函数则是指不能被多次调用的函数,因为多次调用会导致死锁或数据竞争等问题。

2.单片机程序实现可重入和不可重入函数方法的意义:在单片机系统中,多线程或多任务的情况时有发生,因此实现可重入和不可重入函数方法可以提高系统的稳定性和可靠性。

3.实现可重入和不可重入函数方法的常用方法:可采用同步机制(如锁、信号量等)来控制函数的访问权限,避免多线程或多任务之间的冲突。

同时,对于不可重入函数,需要注意避免使用共享变量或使用原子操作来保护临界区代码。

二、单片机程序实现可重入函数的详细步骤:1.函数的可重入性设计原则:可重入性设计原则包括以下几点:避免共享变量、使用同步机制、避免递归调用、避免使用全局变量等。

2.函数参数的传递方式:参数的传递方式会影响函数的可重用性和性能,因此需要选择合适的参数传递方式。

例如,如果参数是复杂数据结构,可以考虑使用传递指针的方式;如果参数是基本数据类型,可以考虑使用寄存器传递。

3.函数内部的变量定义和使用:在函数内部,需要使用局部变量来存储数据,避免使用全局变量或静态变量。

代码重构(一)函数重构规则

代码重构(一)函数重构规则

代码重构(一)函数重构规则
程序代码重构(Refactoring)主要是用来改善代码质量的过程,以满足更高的可读性、可维护性、可测试性等要求,但这并不是一个简单的方法,也不像功能增加那样增加了新的行为能力,而是使现有的代码做一些变更,以达到更好的设计效果。

函数重构是代码重构中最基本的一部分,许多可以用来保持程序的正确性的重构方法都可以用来重构函数。

它可以用来简化和模块化代码,使其更容易理解和更具有复用性,从而实现程序的健全性和可维护性。

以下是函数重构的基本规则:
1.合并重复功能:重构时,如果发现重复的功能,则尽量将它们合并到一个函数中,以简化代码,而不用担心会影响程序的正确性。

2.模块化:将大函数拆分为多个子函数,每个子函数实现一项功能,以满足单一职责原则,每个子函数只做一件事。

3.将变量作用域缩小:将变量应用域从大函数缩小到小函数中,如果在小函数中不需要使用一些变量,则不用定义它。

4.使用更有意义的名字:程序中的变量命名要有意义,避免使用单字母或数字,以便更好的识别代码中的变量。

5.合理使用多函数:将复杂的功能分解为合理的函数,以便多次调用时,程序可读性得到提高,便于维护和维护。

请简述编写函数的原则

请简述编写函数的原则

请简述编写函数的原则编写函数是编程中非常重要的一项技能,它可以帮助我们提高代码的复用性和可维护性。

在编写函数时,有一些原则是我们应该遵循的,下面我将简述这些原则。

1. 函数应具有单一职责原则在编写函数时,应该确保函数只完成一个明确的任务,而不是将多个任务混在一起。

这样可以使函数更加简单、易于理解和维护。

如果一个函数的功能过于复杂,我们可以考虑将其拆分为多个小函数,每个函数负责一个具体的任务。

2. 函数应该具有良好的命名函数的命名应该能够准确地描述函数的功能,使人一目了然。

良好的命名可以使代码更易读,降低出错的可能性。

我们可以使用动词来描述函数的操作,同时要尽量避免使用含糊不清的缩写或简写。

3. 函数应该有明确的输入和输出函数应该明确指定其输入参数和返回值的类型和意义。

这样可以提高函数的可靠性和可测试性,使函数在不同的场景下都能正确地被使用。

4. 函数应该尽量避免使用全局变量全局变量会增加函数之间的耦合度,使得代码难以理解和维护。

因此,在编写函数时,应尽量避免使用全局变量,而是将需要共享的数据通过参数传递给函数。

5. 函数应该具有适当的注释和文档为函数添加适当的注释和文档可以帮助其他人理解函数的功能和用法。

注释应该清晰明了,解释函数的输入、输出以及实现细节等重要信息。

同时,我们还可以使用文档生成工具来生成函数的文档,方便其他人使用和查阅。

6. 函数应该具有异常处理机制在编写函数时,应该考虑到可能出现的异常情况,并为其提供相应的处理机制。

这样可以使函数更加健壮,避免程序因为异常而崩溃或产生错误的结果。

7. 函数的实现应该简洁高效在编写函数时,应尽量避免冗余的代码和不必要的计算。

我们可以使用适当的数据结构和算法来提高函数的效率,从而提高整个程序的性能。

8. 函数应该具有良好的封装性函数应该尽量隐藏其内部的实现细节,只暴露给外部必要的接口。

这样可以提高代码的安全性和可维护性,减少对函数的依赖。

9. 函数应该具有可测试性在编写函数时,应尽量使其具有可测试性。

可重入函数的概念

可重入函数的概念

可重入函数的概念在多线程或有异常控制流的情况下,当某个函数运行到中途时,控制流(也就是当前指令序列)就有可能被打断而去执行另一个函数.而"另一个函数"很有可能是它本身.如果在这种情况下不会出现问题,比如说数据或状态不会被破坏,行为确定。

那么这个函数就被称做"可重入"的.补充:函数是可重入(reentrant)的,是指对于相同的(并且合法的)函数参数(包括无参函数的情况),多次调用此函数产生的行为是可预期的,即函数的行为一致,或者结果相同。

不能保证这一点的函数称为不可重入(non-reentrant)函数。

可重入和线程安全(Thread-Safe)是两个不同的概念:可重入函数一定是线程安全的;线程安全的函数可能是重入的,也可能是不重入的;线程不安全的函数一定是不可重入的。

可重入函数: Reentrant Function线程安全函数: Thread-Safe Function可重入和线程安全不是一个概念。

可重入 => 线程安全可重入函数要解决的问题是,不在函数内部使用静态或全局数据,不返回静态或全局数据,也不调用不可重入函数。

线程安全函数要解决的问题是,多个线程调用函数时访问资源冲突。

函数如果使用静态变量,通过加锁后可以转成线程安全函数,但仍然有可能不是可重入的,比如strtok。

strtok是既不可重入的,也不是线程安全的。

加锁的strtok不是可重入的,但线程安全。

而strtok_r既是可重入的,也是线程安全的。

3. reentrant函数与thread safe函数的区别reentrant函数与是不是多线程无关,如果是reentrant函数,那么要求即使是同一个进程(或线程)同时多次进入该函数时,该函数仍能够正确的运作.该要求还蕴含着,如果是在多线程环境中,不同的两个线程同时进入该函数时,该函数也能够正确的运作.thread safe函数是与多线程有关的,它只是要求不同的两个线程同时对该函数的调用在逻辑上是正确的.从上面的说明可以看出,reentrant的要求比thread safe的要求更加严格.reentrant的函数必是thread safe的,而thread safe的函数未必是reentrant的结论:1. reentrant是对函数相当严格的要求,绝大部分函数都不是reentrant的(APUE上有一个reentrant函数的列表).什么时候我们需要reentrant函数呢?只有一个函数需要在同一个线程中需要进入两次以上,我们才需要reentrant函数.这些情况主要是异步信号处理,递归函数等等.(non-reentrant的递归函数也不一定会出错,出不出错取决于你怎么定义和使用该函数). 大部分时候,我们并不需要函数是reentrant的.2. 在多线程环境当中,只要求多个线程可以同时调用一个函数时,该函数只要是thread safe的就可以了.我们常见的大部分函数都是thread safe的,不确定的话请查阅相关文档.3. reentrant和thread safe的本质的区别就在于,reentrant函数要求即使在同一个线程中任意地进入两次以上,也能正确执行.大家常用的malloc函数是一个典型的non-reentrant但是是thread safe函数,这就说明,我们可以方便的在多个线程中同时调用malloc,但是,如果将malloc函数放入信号处理函数中去,这是一件很危险的事情.4. reentrant函数肯定是thread safe函数,也就是说,non thread safe肯定是non-reentrant函数不能简单的通过加锁,来使得non-reentrant函数变成reentrant 函数"使用的全局变量的函数也不一定是不可重入的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、可重入函数1)什么是可重入性?可重入(reentrant)函数可以由多于一个任务并发使用,而不必担心数据错误。

相反,不可重入(non-reentrant)函数不能由超过一个任务所共享,除非能确保函数的互斥(或者使用信号量,或者在代码的关键部分禁用中断)。

可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。

可重入函数要么使用本地变量,要么在使用全局变量时保护自己的数据。

2)可重入函数:不为连续的调用持有静态数据。

不返回指向静态数据的指针;所有数据都由函数的调用者提供。

使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据。

如果必须访问全局变量,记住利用互斥信号量来保护全局变量。

绝不调用任何不可重入函数。

3)不可重入函数:函数中使用了静态变量,无论是全局静态变量还是局部静态变量。

函数返回静态变量。

函数中调用了不可重入函数。

函数体内使用了静态的数据结构;函数体内调用了malloc()或者free()函数;函数体内调用了其他标准I/O函数。

函数是singleton中的成员函数而且使用了不使用线程独立存储的成员变量。

总的来说,如果一个函数在重入条件下使用了未受保护的共享的资源,那么它是不可重入的。

4)示例在多线程条件下,函数应当是线程安全的,进一步,更强的条件是可重入的。

可重入函数保证了在多线程条件下,函数的状态不会出现错误。

以下分别是一个不可重入和可重入函数的示例://c codestatic int tmp;void func1(int* x, int* y) {tmp=*x;*x=*y;*y=tmp;}void func2(int* x, int* y) {int tmp;tmp=*x;*x=*y;*y=tmp;}func1是不可重入的,func2是可重入的。

因为在多线程条件下,操作系统会在func1还没有执行完的情况下,切换到另一个线程中,那个线程可能再次调用func1,这样状态就错了。

二、函数编写规范1 :对所调用函数的错误返回码要仔细、全面地处理2 :明确函数功能,精确(而不是近似)地实现函数设计3 :编写可重入函数时,应注意局部变量的使用(如编写C/C++ 语言的可重入函数时,应使用auto 即缺省态局部变量或寄存器变量)说明:编写C/C++语言的可重入函数时,不应使用static局部变量,否则必须经过特殊处理,才能使函数具有可重入性。

4 :编写可重入函数时,若使用全局变量(除简单的写或读操作),则应通过关中断、信号量(即P 、V 操作)等手段对其加以保护说明:若对所使用的全局变量不加以保护,则此函数就不具有可重入性,即当多个进程调用此函数时,很有可能使有关全局变量变为不可知状态。

示例:假设Exam是int型全局变量,函数Squre_Exam返回Exam平方值。

那么如下函数不具有可重入性。

unsigned int example( int para ){unsigned int temp;Exam = para; // (**)temp = Square_Exam( );return temp;}此函数若被多个进程调用的话,其结果可能是未知的,因为当(**)语句刚执行完后,另外一个使用本函数的进程可能正好被激活,那么当新激活的进程执行到此函数时,将使Exam 赋与另一个不同的para值,所以当控制重新回到“temp = Square_Exam( )”后,计算出的temp很可能不是预想中的结果。

此函数应如下改进。

unsigned int example( int para ){unsigned int temp;[申请信号量操作] // 若申请不到“信号量”,说明另外的进程正处于Exam = para; // 给Exam赋值并计算其平方过程中(即正在使用此 temp = Square_Exam( ); // 信号),本进程必须等待其释放信号后,才可继 [释放信号量操作] // 续执行。

若申请到信号,则可继续执行,但其// 它进程必须等待本进程释放信号量后,才能再使// 用本信号。

return temp;}5 :在同一项目组应明确规定对接口函数参数的合法性检查应由函数的调用者负责还是由接口函数本身负责,缺省是由函数调用者负责说明:对于模块间接口函数的参数的合法性检查这一问题,往往有两个极端现象,即:要么是调用者和被调用者对参数均不作合法性检查,结果就遗漏了合法性检查这一必要的处理过程,造成问题隐患;要么就是调用者和被调用者均对参数进行合法性检查,这种情况虽不会造成问题,但产生了冗余代码,降低了效率。

6 :防止将函数的参数(尤其是指针)作为工作变量说明:将函数的参数作为工作变量,有可能错误地改变参数内容,所以很危险。

对必须改变的参数,最好先用局部变量代之,最后再将该局部变量的内容赋给该参数。

示例:如下函数的实现就不太好。

void sum_data( unsigned int num, int *data, int *sum ){unsigned int count;*sum = 0;for (count = 0; count < num; count++){*sum += data[count]; // sum成了工作变量,不太好。

}}若改为如下,则更好些。

void sum_data( unsigned int num, int *data, int *sum ){unsigned int count ;int sum_temp;sum_temp = 0;for (count = 0; count < num; count ++){sum_temp += data[count];}*sum = sum_temp;}7 :函数的规模尽量限制在200 行以内说明:不包括注释和空格行。

8 :一个函数仅完成一件功能9 :为简单功能编写函数说明:虽然为仅用一两行就可完成的功能去编函数好象没有必要,但用函数可使功能明确化,增加程序可读性,亦可方便维护、测试。

示例:如下语句的功能不很明显。

value = ( a > b ) ? a : b ;改为如下就很清晰了。

int max (int a, int b){return ((a > b) ? a : b);}value = max (a, b);或改为如下。

#define MAX (a, b) (((a) > (b)) ? (a) : (b))value = MAX (a, b);10:不要设计多用途面面俱到的函数说明:多功能集于一身的函数,很可能使函数的理解、测试、维护等变得困难。

11:函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的输出说明:带有内部“存储器”的函数的功能可能是不可预测的,因为它的输出可能取决于内部存储器(如某标记)的状态。

这样的函数既不易于理解又不利于测试和维护。

在C/C++语言中,函数的static局部变量是函数的内部存储器,有可能使函数的功能不可预测,然而,当某函数的返回值为指针类型时,则必须是STATIC的局部变量的地址作为返回值,若为AUTO类,则返回为错针。

示例:如下函数,其返回值(即功能)是不可预测的。

unsigned int integer_sum( unsigned int base ){unsigned int index;static unsigned int sum = 0; // 注意,是static类型的。

// 若改为auto类型,则函数即变为可预测。

for (index = 1; index <= base; index++){sum += index;}return sum;}12 :尽量不要编写依赖于其他函数内部实现的函数说明:此条为函数独立性的基本要求。

由于目前大部分高级语言都是结构化的,所以通过具体语言的语法要求与编译器功能,基本就可以防止这种情况发生。

但在汇编语言中,由于其灵活性,很可能使函数出现这种情况。

示例:如下是在DOS下TASM的汇编程序例子。

过程Print_Msg的实现依赖于Input_Msg 的具体实现,这种程序是非结构化的,难以维护、修改。

... // 程序代码proc Print_Msg // 过程(函数)Print_Msg... // 程序代码jmp LABEL... // 程序代码endpproc Input_Msg // 过程(函数)Input_Msg... // 程序代码LABEL:... // 程序代码endp13 :避免设计多参数函数,不使用的参数从接口中去掉说明:目的减少函数间接口的复杂度。

14 :非调度函数应减少或防止控制参数,尽量只使用数据参数说明:本建议目的是防止函数间的控制耦合。

调度函数是指根据输入的消息类型或控制命令,来启动相应的功能实体(即函数或过程),而本身并不完成具体功能。

控制参数是指改变函数功能行为的参数,即函数要根据此参数来决定具体怎样工作。

非调度函数的控制参数增加了函数间的控制耦合,很可能使函数间的耦合度增大,并使函数的功能不唯一。

示例:如下函数构造不太合理。

int add_sub( int a, int b, unsigned char add_sub_flg ){if (add_sub_flg == INTEGER_ADD){return (a + b);}else{return (a b);}}不如分为如下两个函数清晰。

int add( int a, int b ){return (a + b);}int sub( int a, int b ){return (a b);}15 :检查函数所有参数输入的有效性16 :检查函数所有非参数输入的有效性,如数据文件、公共变量等说明:函数的输入主要有两种:一种是参数输入;另一种是全局变量、数据文件的输入,即非参数输入。

函数在使用输入之前,应进行必要的检查。

17 :函数名应准确描述函数的功能18 :使用动宾词组为执行某操作的函数命名。

如果是OOP 方法,可以只有动词(名词是对象本身)示例:参照如下方式命名函数。

void print_record( unsigned int rec_ind ) ;int input_record( void ) ;unsigned char get_current_color( void ) ;19 :避免使用无意义或含义不清的动词为函数命名说明:避免用含义不清的动词如process、handle等为函数命名,因为这些动词并没有说明要具体做什么。

20 :函数的返回值要清楚、明了,让使用者不容易忽视错误情况说明:函数的每种出错返回值的意义要清晰、明了、准确,防止使用者误用、理解错误或忽视错误返回码。

相关文档
最新文档