Linux下一个线程accept读TCP socket、另一线程写同socket是否合法?
结论
你描述的跨线程对同一个TCP socket分别执行读、写操作的行为,在Linux平台下是完全合法合规的,不属于未定义行为。
POSIX规范对socket的线程安全特性有明确定义:socket对应的内核接收缓冲区、发送缓冲区是完全独立的,一个线程执行读操作(read/recv/recvfrom等)只会操作接收缓冲区,另一个线程执行写操作(write/send/sendto等)只会操作发送缓冲区,二者在内核层面不会产生访问冲突,不需要额外加锁保护。
注意事项
- 示例代码存在一个需要规避的风险:必须保证线程2调用
send()时,sock变量已经完成了accept()的赋值操作。如果线程2提前访问了还没被accept()初始化的sock值,属于多线程变量访问竞争,会触发未定义行为——这是普通变量的跨线程可见性问题,和socket本身的线程安全性无关。 - 只有当多个线程同时对同一个socket执行同方向的IO操作时(比如两个线程同时读、两个线程同时写),才会出现数据交错、访问竞争的问题,这种场景才需要加锁做同步。
- 为了避免CPU缓存、指令重排导致的
sock值跨线程不可见问题,建议在accept()完成sock赋值后,通过互斥锁、信号量或者原子变量做一次同步,再通知写线程启动对该socket的发送操作。
参考示例(修正逻辑风险后)
// thread #1 // ... int sock = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen); // 执行同步操作,通知线程2 sock已经完成初始化可用 // .. 循环从socket sock读取数据 // thread #2 // ... // 等待同步信号,确认sock完成初始化 int n = send(sock, buffer, 1024); // ...
内容的提问来源于stack exchange,提问作者Joseph Conrad
相关产品推荐
相关产品推荐

