我有一个C ++对象,它创建一个线程来从阻塞的UDP套接字中读取:
mRunning.store(true);
while (mRunning.load(boost::memory_order_consume)) {
...
int size = recvfrom(mSocket, buf, kTextBufSize , 0,
(struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);
if (size > 0) {
//do stuff
}
}
return 0;
(mRunning是一个提升::原子) 从另一个线程调用对象的析构函数并执行此操作:
mRunning.store(false);
#ifdef WIN32
if (mSocket != -1) closesocket(mSocket);
#else
if (mSocket != -1) close(mSocket);
#endif
pthread_join(mThread, NULL);
这似乎有效,但我的一位同事建议,如果recv在阅读过程中被中断,可能会出现问题。这个线程安全吗?关闭阻塞UDP套接字的正确方法是什么? (需要跨平台的OSX / Linux / Windows)
答案 0 :(得分:5)
可能会有很多不同的问题。将我的应用程序从一个FreeBSD版本移动到另一个版本我发现这样的close()在旧内核上正常工作,只是挂起close()直到从较新的recv()返回的东西。 OSX基于FreeBSD:)
从不同线程关闭套接字的便携方式是创建管道和块而不是在recv()中,而是在select()中。当你需要关闭套接字时,写一些东西到管道,select()将解除阻塞,你可以安全地关闭()。
答案 1 :(得分:1)
好recvfrom
本身 是线程安全的。 IIRC所有套接字功能都是。问题是:
recvfrom
下拉取描述符,会发生什么?这是一个好问题,但我怀疑标准是否说明了这一点(我也怀疑实施的具体手册说明了一切)。所以任何实现都是免费的:
recvfrom
失败并返回-1
(ENOTSOCK
,EINVAL
?)close
释放了缓冲区和内部数据结构。显然这只是猜测(以前我错了很多次),但除非您在标准中找到某些内容以支持您可以在接收套接字时关闭套接字的想法, “不安全。
那么,你能做什么?最安全的:使用同步机制确保在close
完成后只有recvfrom
套接字(信号量,互斥量,等等)。
就个人而言,我会在UP
之后的信号量recvfrom
以及DOWN
之前的close
。{/ p>
答案 2 :(得分:0)
你的同事是对的,提升套接字不是线程安全的。
您的选择;