[英]Why do both Java and Go lock socket before write?
Go internal/poll/fd_unix.go 代码在这里
// Write implements io.Writer.
func (fd *FD) Write(p []byte) (int, error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
......
}
java 代码 java.net.SocketOutputStream#socketWrite 在这里
private void socketWrite(byte b[], int off, int len) throws IOException {
if (len <= 0 || off < 0 || len > b.length - off) {
if (len == 0) {
return;
}
throw new ArrayIndexOutOfBoundsException("len == " + len
+ " off == " + off + " buffer length == " + b.length);
}
FileDescriptor fd = impl.acquireFD();
try {
socketWrite0(fd, b, off, len);
} catch (SocketException se) {
......
我不知道为什么我们需要锁定它。 另一个问题是 syscall.Write 等效于 <unistd.h> 写入 C 吗?
好吧,只回答 Java 部分:
既然我们已经在讨论实现细节,为什么要停留在 Java 级别? 本机方法socketWrite0的 OpenJdk 实现的 C 源代码跨越约 70 行代码,显然不是原子的。 它执行诸如使用malloc
和free
等分配和释放 memory 之类的事情,并且涉及相当多的非平凡逻辑。 在那个时候,它调用的NET_Send
function 是否直接将数据直接转换为每个支持的平台上的系统调用都不再重要了。
要点是:实现在循环中调用此NET_Send
。 所以无论这是否是单独的线程安全的,如果它被多个线程同时调用,output 将被交错(最好的情况)。
好的,假设没有锁定机制,并且两个并发线程/进程正在向套接字写入一些数据。 让我们举一个过于简单的例子。
Java 应用程序想要写:“你好?你好吗。”。
Go 应用程序想要写:“稍后见。”
这两个应用程序都试图同时写入。
您期望的 output 是:
Hello! How are you?
See you later.
但是,您很有可能会得到类似的东西。
HellSee o! How See you are later.
you?
每当资源在不同的进程/线程之间共享并且没有适当的锁定机制时。 遇到不一致和意外行为的可能性很高。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.