【发布时间】:2013-12-19 12:00:49
【问题描述】:
我在 Windows 中使用 I/O 完成端口,我有一个名为“Stream”的对象,它类似于并抽象了一个 HANDLE(因此它可以是套接字、文件等)。
当我调用 Stream::read() 或 Stream::write() 时(因此,对于文件,ReadFile()/WriteFile() 和对于套接字的 WSARecv()/WSASend()),我分配了一个新的 OVERLAPPED 结构,以便发出一个挂起的 I/O 请求,该请求将由其他线程在 IOCP 循环中完成。
然后,当 IOCP 循环完成 OVERLAPPED 结构时,它将在那里被销毁。如果是这种情况,则从 IOCP 循环再次调用 Stream::read() 或 Stream::write(),它们将实例化新的 OVERLAPPED 结构,并且它将永远存在。
这很好用。但现在我想通过添加 OVERLAPPED 对象的缓存来改进这一点: 当我的 Stream 对象进行大量读取或写入时,缓存 OVERLAPPED 结构绝对有意义。
但是现在出现了一个问题:当我释放 Stream 对象时,我必须释放缓存的 OVERLAPPED 结构,但是我如何知道它们是否已经完成或仍在等待中,并且最近 IOCP 循环之一将完成呢?所以,这里需要一个 atomic 引用计数,但现在的问题是,如果我使用原子引用计数器,我必须为每个读取或写入操作增加该引用计数器,并减少每个 IOCP OVERLAPPED 结构或流删除的循环完成,这在服务器中是 很多 操作,所以我将通过增加/减少 很多 原子计数器来结束em>很多次。
这会对多线程的并发性产生非常负面的影响吗?这是我唯一担心的问题,阻止我为每个 OVERLAPPED 结构放置这个原子引用计数器。
我的担忧毫无根据吗?
我认为这是一个需要指出的重要话题,关于 SO 的问题,看看其他人对此的想法以及使用 IOCP 缓存 OVERLAPPED 结构的方法,是值得的。 如果可能的话,我希望在不使用原子引用计数器的情况下找到一个聪明的解决方案。
【问题讨论】:
-
当操作需要几毫秒时,您会担心纳秒。这非常符合“万恶之源”的口头禅。
-
'那么,当 OVERLAPPED 结构将被 IOCP 循环完成时,它将在那里被销毁。' - 你为什么要毁掉它?它应该是流类的成员,或者是在 WSA 调用中缓存和使用的某个其他“IOCPbuffer”类的成员,其数据在 IOCP 完成后应用于其流,然后再释放回其池。
-
Martin,是的,这正是我想要实现的,我想知道原子引用计数器是否可以用于那些“IOCPbuffer”结构。汉斯,问题不在于纳秒或毫秒,而在于锁定,一堆LOCKed指令会影响线程并发,因为当一个内存区域(例如原子计数器)被原子读/写时,其他内核必须等待完成原子事务。
-
AFAIK,你不需要任何原子计数器。如果您正在缓存/池化这些实例,则永远不会销毁它们,只需重新池化它们即可。池本身需要一个锁,但处理锁所花费的时间肯定会因避免不断创建/销毁类实例而被淹没。
-
哦.. 等一下,您是否正在向多个客户端发送相同的缓冲区?这就是你需要 refCount 的原因吗?
标签: windows multithreading sockets atomic iocp