执行此操作是否安全:
int fd;
void thread_main()
{
char buf[M];
ssize_t r = read(fd, buf, M);
assert(r == M);
...
}
int main()
{
fd = open("/dev/urandom", O_RDONLY);
for (int i = 0; i < N; i++)
start_thread(i);
for (int i = 0; i < N; i++)
join_thread(i);
}
也就是说:在从主线程中将
open(2)
编码为"/dev/urandom"
之后,从不同线程上下文中不同步它的read(2)
是否安全?断言在什么情况下会被开火?两个线程会获得相同的数据吗?可能出什么问题了?
最佳答案
您的代码是安全的,因为它不会崩溃。 assert
将永远不会触发。没有两个线程会(应该)获得相同的随机数据(这是极不可能的,但两个线程也有可能获得两个偶然地相同的“不同”随机序列,因此不能100%保证)。/dev/urandom
绝不会阻塞或返回比您尝试读取的字节少的字节,但是,如果您读取的字节数足够多,它将最终耗尽熵,因此随机数的质量最终将略有下降。通常,这仍然足够好,并且还需要一段时间才能实现,但这是需要注意的事情(大多数人不需要关心,但这可能 Not Acceptable ,具体取决于您的操作) 。read
/write
是线程安全的(因为它们不会崩溃或损坏数据或使描述符保持未定义状态),并且在这种特殊情况下,也不应在对不同进程的读取/写入之间混合/分割字节。但是,通常,read
/write
不保证此。在某些设备上,它们可能会在并发读/写操作中混合数据。
但是,这应该不成问题,因为如果您获得一些其他随机位而其他人在两者之间获得了(不同的)位,则随机位仍然是随机的。
如果您认为这对您来说是个问题,请使用readv
,它可以保证严格的原子性(永远不要混合/混合)。进出readv
/writev
的所有内容始终作为一个原子单位进行处理(如在管道上,当超过PIPE_BUF
的大小时,如rodrigo所指出)。
关于c - Linux 3.5 : Safe to `read(2)` from same fd `open(2)` `/dev/urandom` from multiple threads?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12245054/