我曾经认为所有可重入函数都是线程安全的.但我在Wiki中阅读了Reentrancy页面,它发布了"完全可重入但不是线程安全的代码.因为它不能确保全局数据在执行期间处于一致状态"
int t;
void swap(int *x, int *y)
{
int s;
s = t; // save global variable
t = *x;
*x = *y;
// hardware interrupt might invoke isr() here!
*y = t;
t = s; // restore global variable
}
void isr()
{
int x = 1, y = 2;
swap(&x, &y);
}
Run Code Online (Sandbox Code Playgroud)
我不明白它的解释.为什么这个函数不是线程安全的?是因为int t在线程执行期间全局变量会被更改吗?
这种类型的重入的技巧是第一次调用的执行在执行第二次调用时停止.就像一个子功能调用.第二个呼叫完成后,第一个呼叫继续.因为该函数在进入时保存t的状态并在退出时恢复它,所以当第一次调用继续时,没有任何改变.因此,无论第一次调用的中断位置如何,您始终都有一个已定义且严格的执行顺序.
当此函数在多个线程中运行时,所有执行都是并行完成的,即使与多核CPU完全并行也是如此.所有线程都没有定义的执行顺序,只在单个线程中.因此,t的值可以随时由其他一个线程更改.
为了给出更通用的答案,重入仅在函数级别。这意味着函数的一次调用不会改变可以改变第二次调用功能的状态。
在给出的例子中,全局变量在函数的两次调用之间没有改变。函数内部发生的事情对函数的每次调用没有影响。
不可重入函数的一个例子是 strtok
例如,不可能用它嵌套 2 个解析循环:
/* To read a several lines of comma separated numbers */
char buff[WHATEVER], *p1, *p2;
p1 = strtok(buff, "\n");
while(p1) {
p2 = strtok(p1, ",");
while(p2) {
atoi(p2);
p2 = strtok(NULL, ",");
}
}
p1 = strtok(NULL, "\n");
}
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为外部 strtok 循环的状态被第二次调用破坏了(必须使用可重入变体strtok_r)。
| 归档时间: |
|
| 查看次数: |
3177 次 |
| 最近记录: |