在iPhone OS 3.1.2上sscanf线程安全吗?
我刚刚花了一整天的时间调试一个随机bug,这时我终于意识到问题是sscanf被多个线程调用了 我通过运行以下代码确认了这一点,该代码在SnowLeopard上正常工作,但在我的iphone上使用os 3.1.2会产生非常奇怪的结果。它也可以在模拟器中正常工作 在iPhone上,解析的数字将是字符串中使用的数字的随机组合 如果有人能检查一下这是不是一个普遍的问题,或者这是我这边的一个错误,那将是非常有帮助的在iPhone OS 3.1.2上sscanf线程安全吗?,iphone,c,thread-safety,scanf,Iphone,C,Thread Safety,Scanf,我刚刚花了一整天的时间调试一个随机bug,这时我终于意识到问题是sscanf被多个线程调用了 我通过运行以下代码确认了这一点,该代码在SnowLeopard上正常工作,但在我的iphone上使用os 3.1.2会产生非常奇怪的结果。它也可以在模拟器中正常工作 在iPhone上,解析的数字将是字符串中使用的数字的随机组合 如果有人能检查一下这是不是一个普遍的问题,或者这是我这边的一个错误,那将是非常有帮助的 - (void)testIt { [NSThread detachNewThre
- (void)testIt
{
[NSThread detachNewThreadSelector:@selector(scanfTest) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(scanfTest) toTarget:self withObject:nil];
}
- (void)scanfTest
{
while (true)
{
float value = 0.0f;
sscanf("456", "%f", &value);
sscanf( "1.63", "%f", &value);
if (value != 1.63f)
NSLog(@"strange value is %f", value);
}
}
我做了进一步的检查,似乎只有浮点数是个问题。此代码有效
- (void)scanfTest4
{
while (true)
{
int year = 0;
int month = 0;
int day = 0;
sscanf("20090131", "%4d%2d%2d", &year, &month, &day);
sscanf("19840715", "%4d%2d%2d", &year, &month, &day);
if (year != 1984 || month != 7 || day != 15)
NSLog(@"bla");
}
}
这段代码失败了,出现了同样的随机数字问题
- (void)scanfTest4
{
while (true)
{
int year = 0;
int month = 0;
float day = 0.0f;
sscanf("20090131", "%4d%2d%2f", &year, &month, &day);
sscanf("19840715", "%4d%2d%2f", &year, &month, &day);
if (year != 1984 || month != 7 || day != 15.0f)
NSLog(@"bla");
}
}
sscanf不是线程安全期。它是在线程存在之前编写的,其设计要求它使用内部静态临时变量。sprintf也是如此 我知道你的情况,不管怎么说,sscanf的杀伤力太大了。只需使用
atof
。SUSv2说():
此定义的所有接口
规范将是线程安全的,
除了以下接口
不必是线程安全的
sscanf()
不在不需要线程安全的接口列表中
这并不是说iPhone是SUSv2兼容的,但我认为至少它解释了为什么你的代码应该在雪豹上工作。另外,我手头上没有最新的POSIX规范,所以我冒着一点风险假设它自1997年以来没有改变。谢谢John和Stephen
我可以确认在这种情况下使用atof和strtof都是安全的。如果我可能会问,当您可以使用NSString数字转换时,为什么需要使用sscanf/atof?您看到的输出与期望的输出相比是什么?比较2个浮点值(即:1.63==1.63)本身就充满了困难。要基于Jarret Hardie的评论:而不是直接比较浮点值是否相等,通常需要用一个小的(1e-6)ε进行一些
if(fabs(float1-float2)
。这告诉你它们是否足够接近,可以被认为是相等的,而不是完全相同的。正如我所提到的,我得到的输出是从1到1456或13.6的任何数字,或者可以由数字“456”“1.63”组合的任何数字,我知道我知道。。。问题是,如果我不使用sscanf(“456”、“%f”、&value);所有的一切都如预期的那样工作,所以很明显,内部状态是共享的。只要两个线程扫描相同的字符串,一切都很好。不要使用atof。改用标准的Cstrof()
函数,该函数具有更简单的错误处理,通常更易使用。您能解释一下sscanf的定义中要求它使用静态变量的是什么吗?@Steve Jessop,它不需要,但它需要跟踪它在格式字符串中的长度等等。我想,仅仅使用一个静电传感器是很容易的。“但我有点被提问者得到的结果难住了。”史蒂夫·杰索普。所以可能要求太强了。当然可以想象一个不使用静态的实现。但它确实需要一个相当大的临时存储空间,并且它调用了许多其他crt代码作为帮助。典型的实现是将输入字符串转换为一个“假装”文件,然后将其传递给fscanf(或者更确切地说,它和fscanf共享一个公共worker)。删除原始crt中的所有静态是一项相当艰巨的工作,你仍然无法保护自己免受缓冲区溢出的影响。如果没有静态,我想你已经为OSX和模拟器做了。我也检查了SUSv2,因此对John的“sscanf不是线程安全期”感到有点困惑sscanf不是我所知道的POSIX函数之一。我希望它使用区域设置,这总是一个蠕虫线程,但您看到的行为更像是将部分输入复制到静态中。对我来说,这是令人费解的,但并不明显是疯狂的,所以也许我只是错过了一些显而易见的原因,为什么sscanf工作得更好/如果这样做的话。我注意到,NSScanner被明确定义为不是线程安全的。是否iPhone上的sscanf使用的是针对区域设置配置的全局NSScanner?我现在要停止猜测了,最终我对Mac和iPhone的了解大致如下:0;-)出于性能方面的原因,我决定在应用程序的这一部分严格使用C语言。我以前使用的cocoa版本无法进一步优化,而向C语言的转换带来了巨大的性能提升。