[英]whether rand_r is real thread safe?
好吧,rand_r函数应该是线程安全的函数。 但是,通过其实现,我无法相信它可以使其自身不会被其他线程改变。 假设两个线程将使用相同的变量种子同时调用rand_r。 因此将发生读写竞争。 下面列出了由glibc实现的代码rand_r。 有人知道为什么rand_r被称为线程安全吗?
int
rand_r (unsigned int *seed)
{
unsigned int next = *seed;
int result;
next *= 1103515245;
next += 12345;
result = (unsigned int) (next / 65536) % 2048;
next *= 1103515245;
next += 12345;
result <<= 10;
result ^= (unsigned int) (next / 65536) % 1024;
next *= 1103515245;
next += 12345;
result <<= 10;
result ^= (unsigned int) (next / 65536) % 1024;
*seed = next;
return result;
}
您可以想到三个线程安全级别,为便于参考,在此将其编号。
1)根本不是线程安全的。 从多个线程同时调用该函数是不安全的。 例如, strtok
。
2)关于系统的线程安全。 如果不同的调用对不同的数据进行操作,则可以安全地从多个线程同时调用该函数。 例如, rand_r
, memcpy
。
3)关于数据的线程安全。 从多个线程并发调用该函数是安全的,即使作用于同一数据也是如此。 例如pthread_mutex_lock
。
rand_r
处于级别2,在C上下文中的约定(特别是在POSIX规范中)是将其称为“线程安全”。
在某些其他语言(例如Java)中,惯例是将级别3称为“线程安全”,而将其他所有内容称为“非线程安全”。 因此,例如java.util.Vector
是“线程安全的”,而java.util.ArrayList
是“不是线程安全的”。 当然, java.util.ArrayList
所有方法都处于2级。因此,来自Java的程序员自然可以将rand_r
和memcpy
称为“不是线程安全的”。
在C语言中,约定有所不同,可能是因为内部同步数据结构开始时很少见。 在C的上下文中,您可能会问“文件句柄是否是线程安全的?”,并且正在谈论级别3,但是当询问“此函数是否是线程安全的吗?”时,您可能会问。 通常表示2级
rand_r
是线程安全的,因为该函数是完全纯函数。 除了参数之外,它不会读取或修改任何状态。 因此可以安全地同时调用它。
这与大多数将rand
(状态)(状态)保存在全局变量中的rand
函数不同。
假设两个线程将使用相同的变量种子同时调用rand_r。
我假设你的意思是这样的
int globalSeed;
//thread 1
rand_r(&globalSeed);
//thread 2
rand_r(&globalSeed);
这并不意味着该函数不是线程安全的,而是意味着您通过提供输出参数来以非线程安全的方式使用它,该输出参数可以被另一个线程访问/修改。
这与将函数结果写入可以由另一个线程访问/修改的全局变量相同。 这并不意味着该函数不是线程安全的,这意味着您的代码不是线程安全的。
因为它修改了种子,所以种子被传递了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.