5

这样做是否安全:

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)ing之后,从不同线程上下文中不同步它是否安全?"/dev/urandom"read(2)

什么情况下assert会火?两个线程会得到相同的数据吗?会出什么问题?

4

2 回答 2

6

你的代码是安全的,因为它不会崩溃。assert永远不会触发。没有两个线程将(应该)获得相同的随机数据(两个线程获得两个“不同”随机序列的可能性很小,但仍然有可能偶然相同,因此不能 100% 保证这一点)。

/dev/urandom永远不会阻塞或返回比您尝试读取的字节更少的字节,但是,如果您读取的数量足够大,它最终会耗尽熵,因此随机数的质量最终会略有下降。通常,这仍然足够好,并且在此之前也需要一段时间,但这是需要注意的事情(大多数人不需要关心,但可能无法接受,这取决于你做什么) .

read/write是线程安全的(只要它们不会崩溃或损坏数据或使描述符处于未定义状态),并且在这种特殊情况下,也不在对不同进程的读取/写入之间混合/拆分字节。但是,通常read/write 不保证这一点。它们可能会在某些设备上混合并发读/写数据。

但是,这应该不是问题,因为如果您获得一些其他随机位并且其他人获得介于两者之间的一些(不同)位,则随机位仍然是随机的。
如果您认为这对您来说是个问题,请使用readv保证严格的原子性(永远不会混合/混合)。任何进出readv/writev的东西总是作为一个原子单元处理(除了在管道上,当超过 的大小时PIPE_BUF,正如 rodrigo 所指出的那样)。

于 2012-09-03T10:48:36.973 回答
2

read 是线程安全的,因为它是一个系统调用,如果您从多个线程进行多次读取,则每次读取都将被串行处理。也就是说线程 A 会读取 M 个字节,线程 B 会读取下一个 M 个字节,依此类推,而不是线程 A 读取几个字节,线程 B 读取几个字节,然后线程 A 读取更多字节。

写也是一样。

多个线程进行读取和写入的常见问题是,它们通常一次读取/写入 1 个字符,因此有很多机会混淆输入和输出的来源 - 通常混淆是由存在于读/写之上的语言运行时库添加

于 2012-09-03T09:31:51.163 回答