go internal/poll/fdïu 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中写入?
2条答案
按热度按时间6ojccjat1#
好的,假设没有锁定机制,两个并发线程/进程正在向套接字写入一些数据。让我们举一个过于简单的例子。
java应用程序想写:“你好!“你好吗?”。
去申请要写:“回头见。”
这两个应用程序都试图同时编写。
您期望的输出是:
然而,很有可能你会得到这样的东西。
当一个资源在不同的进程/线程之间共享并且没有适当的锁定机制时。遇到不一致和意外行为的可能性很大。
hlswsv352#
好吧,只回答java部分:
既然我们已经在讨论实现细节,为什么还要停留在java级别呢?本机方法socketwrite0的openjdk实现的c源代码跨越约70行代码,显然不是原子的。它可以使用
malloc
以及free
,并涉及相当多的非琐碎逻辑。不管NET_Send
它调用的函数实际上直接发送数据,在每个受支持的平台上都转换成syscall,在这一点上已经不再重要了。要点是:实现调用
NET_Send
-循环中的函数。因此,无论这是否是线程安全的,如果它是由多个线程并发调用的,那么输出将是交错的(最佳情况)。