这样做是否安全:
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)
是不安全的?
在什么情况下断言会引发火灾?两个线程会得到相同的数据吗?可能出现什么问题?
答案 0 :(得分:6)
您的代码是安全的,因为它不会崩溃。 assert
永远不会触发。没有两个线程(应该)得到相同的随机数据(这是非常不可能的,但仍然有可能两个线程得到两个“不同”的随机序列 inlateide 相同,所以这不能100%保证。)
/dev/urandom
永远不会阻止或返回比您尝试读取的字节数更少的字节数,但是,如果读取的数量足够大,它最终会耗尽熵,因此随机数的质量最终会略微降低。通常情况下,这仍然是足够好的,在这种情况发生之前还需要一段时间,但这是需要注意的事情(大多数人不需要关心,但可能不可以接受,取决于你做了什么)。
read
/ write
是线程安全的(只要它们不会崩溃或损坏数据或将描述符保留在未定义的状态)并且在这种特殊情况下不应该混合/在不同进程的读/写之间分配字节。但是,一般情况下,read
/ write
不保证此。他们可能在某些设备上混合并发读/写数据。
然而,它不应该是一个问题,因为如果你得到一些其他的随机位,而其他人在中间得到一些(不同的)位,则随机位仍然是随机的。
如果您认为这对您来说是一个问题,请使用readv
保证严格的原子性(无需混合/混合)。进出readv
/ writev
的任何内容都将作为一个原子单元处理(管道上的除外,当超过PIPE_BUF
的大小时,罗德里戈指出。
答案 1 :(得分:2)
读取是线程安全的,因为它是一个系统调用,如果你从多个线程进行多次读取,每次读取都将被串行处理。也就是说线程A将读取M个字节,线程B将读取下一个M字节,依此类推,而不是线程A读取几个字节,线程B读取几个字节,然后线程A读取更多字节。
写作也是如此。
多个线程执行读写操作的常见问题是,它们通常一次读/写1个字符,所以有很多机会混淆输入输入和输出来自 - 并经常混淆被存在于读/写
之上的语言运行库库添加