
TCB — (Task Control Blank )OS_TCB ptcb 是任务控制块结构体指针,用于传递任务控制块地址,在uCOS内所用任务公用一个TCB,每个任务进行 *** 作都会通过地址进行访问才会生效!该函数是删除任务钩子函数,用于在删除任务时进行相应用户 *** 作,比如释放临界变量啊,控制其他任务同步等等。
ptcb = ptcb; //预防编译出错
因为有些编译器在预编译时发现入口参数未使用会出现警告,通过这句就表示已经使用,相应就不会报错了!
希望你满意!
开发实时占先式的 *** 作系统,可重入函数是非用不可的。可重入函数可以被一个以上的任务调用,而不必担心数据被破坏。可重入函数任何时候都可以被中断,一段时间后又可以运行,而应用数据不会丢失。使得函数具有可重入性必须使得函数能够满足下列三个条件之一:
① 不使用共享资源;
② 在使用共享资源时关中断,使用完毕后再开中断;
③ 在使用共享资源时申请信号量,使用完后释放信号量。
这些条件在标准C中编程很容易实现,但是在Keil C51中就比较麻烦。因为标准C是把局部变量分配到用户堆栈中(动态分配),而Keil C51将局部变量分配到寄存器或内存固定地址(静态分配),并通过变量覆盖分析的方法,使多个函数的局部变量使用相同的内存地址以减少内存占用。在Keil C51中,如果局部变量分配在寄存器中还好些,如果局部变量分配在内存中就比较麻烦。
若对所使用的全局变量不加以保护,则此函数就不具有可重入性,即当多个进程调用此函数时,很有可能使有关全局变量变为不可知状态。
函数不可重入的原因主要如下:
<!--[if !supportLists]-->(1) <!--[endif]-->函数使用了static静态数据结构
如:struct passwd getpwuid(uid_t uid);
struct passwd getpwnam(const char name);
struct passwd getpwent(void);
以上3个函数都是返回一个指向passwd结构的指针,而该passwd结构通常都是函数中static变量,其内容在每次调用以上函数时都会被重写。因此,当进程主程序与信号处理程序中均调用了以上函数时,冲突就产生了。
<!--[if !supportLists]-->(2) <!--[endif]-->函数调用了malloc和free函数,正如文章最开始所提到的;
<!--[if !supportLists]-->(3) <!--[endif]-->函数为标准I/O的库函数,因为大多数的标准I/O库函数的实现都使用了global全局数据结构;
因此,若要写可重入性函数的做法通常是我们在函数中只修改局部变量,而不改变全局变量,或尽量不使用全局变量、静态static变量。
事实上,与可重入性函数(reentrant function)对应的还有可重入内核(reentrant kernel),其区别和联系在《深入理解Linux内核》上有较详细的讲解。
若一个程序或子程序可以安全的被并行执行,则称其为可重入(reentrant或re-entrant)的;即,当该子程序正在运行时,可以再次进入并执行它。若一个函数是可重入的,则该函数:不能含有静态(全局)非常量数据。 不能返回静态(全局)非常量数据的地址。 只能处理由调用者提供的数据。 不能依赖于单实例模式资源的锁。 不能调用不可重入的函数。 多'用户/对象/进程优先级'以及多进程一般会使得对可重入代码的控制变得复杂。同时,IO代码通常不是可重入的,因为他们依赖于像磁盘这样共享的、单独的资源。可重入性是函数编程语言的关键特性之一。 例子在以下的C语言代码中,函数f和函数g都不是可重入的。int g_var = 1;int f(){ g_var = g_var + 2; return g_var;}int g(){ return f() + 2;}以上代码中,f使用了全局变量 g_var,所以,如果两个线程同时执行它并访问g_var,则返回的结果取决于执行的时间。因此,f不可重入。而g调用了f,所以它也不可重入。稍作修改后,两个函数都是可重入的:int f(int i){ return i + 2;}int g(int i){ return f(i) + 2;}
可重入函数(即可以被中断的函数)可以被一个以上的任务调用,而不担心数据破坏。可重入函数在任何时候都可以被中断,而一段时间之后又可以恢复运行,而相应的数据不会破坏或者丢失。
可重入函数使用的变量有两种情况:
1使用局部变量,变量保存在CPU寄存器中或者堆栈中;
2使用全局变量,但是这时候要注意保护全局变量(防止任务中断后被其它任务改变变量)。
1
2
3
4
5
void strcpy(dest,src)
{
while( dest++ = src ++){;}
dest = NUL;
}
分析:上面的函数用于字符串复制,而参数是存放在堆栈中的,故而改函数可以被多任务调用,而不必担心各个任务调用期间会互相破坏对方的指针。
基本上下面的函数都是不可重入的:
1函数内使用了静态的数据。
2函数内使用了malloc()或者free()函数的。
3函数内调用了标准的I/O函数的。
1
2
3
4
5
6
7
int temp;
void swap(int ex1,int ex2)
{
temp = ex1;//(1)
ex1 = ex2;
ex2 = temp;
}
分析:该函数中的全局变量temp是的函数变成了一个不可重入的函数,因为在多任务系统中,假如在任务1中调用swap函数,而程序执行到(1)处时被中断,进而执行其它的任务2,而刚好任务2也调用了swap函数,则temp里存的值则会被任务2改变。从而回到任务1被中断处继续执行的时候,temp里存的值已经不再是原来存的temp值了,进而产生了错误。
常用的可重入函数的方法有:
1不要使用全局变量,防止别的代码覆盖这些变量的值。
2调用这类函数之前先关掉中断,调用完之后马上打开中断。防止函数执行期间被中断进入别的任务执行。
3使用信号量(互斥条件)。
总之:要保证中断是安全的
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)