第一范文网 - 专业文章范例文档资料分享平台

完成端口

来源:用户分享 时间:2025/10/2 7:02:36 本文由loading 分享 下载这篇文档手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:xxxxxxx或QQ:xxxxxx 处理(尽可能给您提供完整文档),感谢您的支持与谅解。

1.

2. typedef struct _WSABUF {

3. ULONG len; /* the length of the buffer */

4. __field_bcount(len) CHAR FAR *buf; /* the pointer to the buff

er */ 5.

6. } WSABUF, FAR * LPWSABUF;

而且好心的微软还附赠了注释,真不容易….

看到了吗?如果对于里面的一些奇怪符号你们看不懂的话,也不用管他,只用看到一个ULONG和一个CHAR*就可以了,这不就是一个是缓冲区长度,一个是缓冲区指针么?至于那个什么 FAR…..让他见鬼去吧,现在已经是32位和64位时代了……

这里需要注意的,我们的应用程序接到数据到达的通知的时候,其实数据已经被咱们的主机接收下来了,我们直接通过这个WSABUF指针去系统缓冲区拿数据就好了,而不像那些没用重叠I/O的模型,接收到有数据到达的通知的时候还得自己去另外recv,太低端了……这也是为什么重叠I/O比其他的I/O性能要好的原因之一。

?

LPWSAOVERLAPPED lpOverlapped

这个参数就是我们所谓的重叠结构了,就是这样定义,然后在有Socket连接进来的时候,生成并初始化一下,然后在投递第一个完成请求的时候,作为参数传递进去就可以,

[cpp] view plaincopy

1. OVERLAPPED* m_pol = new OVERLAPPED; 2.

3. eroMemory(m_pol, sizeof(OVERLAPPED));

在第一个重叠请求完毕之后,我们的这个OVERLAPPED 结构体里,就会被分配有效的系统参数了,并且我们是需要每一个Socket上的每一个I/O操作类型,都要有一个唯一的Overlapped结构去标识。

这样,投递一个WSARecv就讲完了,至于_DoRecv()需要做些什么呢?其实就是做两件事:

(1) 把WSARecv里这个缓冲区里收到的数据显示出来; (2) 发出下一个WSARecv(); Over……

至此,我们终于深深的喘口气了,完成端口的大部分工作我们也完成了,也非常感谢各位耐心的看我这么枯燥的文字一直看到这里,真是一个不容易的事情!! 【第八步】如何关闭完成端口 休息完毕,我们继续……

各位看官不要高兴得太早,虽然我们已经让我们的完成端口顺利运作起来了,但是在退出的时候如何释放资源咱们也是要知道的,否则岂不是功亏一篑….. 从前面的章节中,我们已经了解到,Worker线程一旦进入了

GetQueuedCompletionStatus()的阶段,就会进入睡眠状态,INFINITE的等待完成端口中,如果完成端口上一直都没有已经完成的I/O请求,那么这些线程将无法被唤醒,这也意味着线程没法正常退出。

熟悉或者不熟悉多线程编程的朋友,都应该知道,如果在线程睡眠的时候,简单粗暴的就把线程关闭掉的话,那是会一个很可怕的事情,因为很多线程体内很多资源都来不及释放掉,无论是这些资源最后是否会被操作系统回收,我们作为一个C++程序员来讲,都不应该允许这样的事情出现。

所以我们必须得有一个很优雅的,让线程自己退出的办法。 这时会用到我们这次见到的与完成端口有关的最后一个API,叫 PostQueuedCompletionStatus(),从名字上也能看得出来,这个是和

GetQueuedCompletionStatus() 函数相对的,这个函数的用途就是可以让我们手动的添加一个完成端口I/O操作,这样处于睡眠等待的状态的线程就会有一个被唤醒,如果为我们每一个Worker线程都调用一次PostQueuedCompletionStatus()的话,那么所有的线程也就会因此而被唤醒了。

PostQueuedCompletionStatus()函数的原型是这样定义的:

[cpp] view plaincopy

1. BOOL WINAPI PostQueuedCompletionStatus(

2. __in HANDLE CompletionPort,

3. __in DWORD dwNumberOfBytesTransferred, 4. __in ULONG_PTR dwCompletionKey, 5. __in_opt LPOVERLAPPED lpOverlapped 6. );

我们可以看到,这个函数的参数几乎和GetQueuedCompletionStatus()的一模一样,都是需要把我们建立的完成端口传进去,然后后面的三个参数是 传输字节数、结构体参数、重叠结构的指针.

注意,这里也有一个很神奇的事情,正常情况下,GetQueuedCompletionStatus()获取回来的参数本来是应该是系统帮我们填充的,或者是在绑定完成端口时就有的,但是我们这里却可以直接使用PostQueuedCompletionStatus()直接将后面三个参数传递给GetQueuedCompletionStatus(),这样就非常方便了。

例如,我们为了能够实现通知线程退出的效果,可以自己定义一些约定,比如把这后面三个参数设置一个特殊的值,然后Worker线程接收到完成通知之后,通过判断这3个参数中是否出现了特殊的值,来决定是否是应该退出线程了。 例如我们在调用的时候,就可以这样:

[cpp] view plaincopy

1. for (int i = 0; i < m_nThreads; i++) 2. {

3. PostQueuedCompletionStatus(m_hIOCompletionPort, 0, (DWORD) NULL, NULL)

; 4. }

为每一个线程都发送一个完成端口数据包,有几个线程就发送几遍,把其中的dwCompletionKey参数设置为NULL,这样每一个Worker线程在接收到这个完成通知的时候,再自己判断一下这个参数是否被设置成了NULL,因为正常情况下,这个参数总是会有一个非NULL的指针传入进来的,如果Worker发现这个参数被设置成了NULL,那么Worker线程就会知道,这是应用程序再向Worker线程发送的退出指令,这样Worker线程在内部就可以自己很“优雅”的退出了……

学会了吗?

但是这里有一个很明显的问题,聪明的朋友一定想到了,而且只有想到了这个问题的人,才算是真正看明白了这个方法。

我们只是发送了m_nThreads次,我们如何能确保每一个Worker线程正好就收到一个,然后所有的线程都正好退出呢?是的,我们没有办法保证,所以很有可能一个Worker线程处理完一个完成请求之后,发生了某些事情,结果又再次去循环接收下一个完成请求了,这样就会造成有的Worker线程没有办法接收到我们发出的退出通知。 所以,我们在退出的时候,一定要确保Worker线程只调用一次

GetQueuedCompletionStatus(),这就需要我们自己想办法了,各位请参考我在Worker线程中实现的代码,我搭配了一个退出的Event,在退出的时候SetEvent一下,来确保Worker线程每次就只会调用一轮 GetQueuedCompletionStatus() ,这样就应该比较安全了。 另外,在Vista/Win7系统中,我们还有一个更简单的方式,我们可以直接CloseHandle关掉完成端口的句柄,这样所有在GetQueuedCompletionStatus()的线程都会被唤醒,并且返回FALSE,这时调用GetLastError()获取错误码时,会返回ERROR_INVALID_HANDLE,这样每一个Worker线程就可以通过这种方式轻松简单的知道自己该退出了。当然,如果我们不能保证我们的应用程序只在Vista/Win7中,那还是老老实实的PostQueuedCompletionStatus()吧。

最后,在系统释放资源的最后阶段,切记,因为完成端口同样也是一个Handle,所以也得用CloseHandle将这个句柄关闭,当然还要记得用closesocket关闭一系列的socket,还有别的各种指针什么的,这都是作为一个合格的C++程序员的基本功,在这里就不多说了,如果还是有不太清楚的朋友,请参考我的示例代码中的 StopListen() 和DeInitialize() 函数。

六. 完成端口使用中的注意事项

终于到了文章的结尾了,不知道各位朋友是基本学会了完成端口的使用了呢,还是被完成端口以及我这么多口水的文章折磨得不行了……

最后再补充一些前面没有提到了,实际应用中的一些注意事项吧。 1. Socket的通信缓冲区设置成多大合适?

搜索更多关于: 完成端口 的文档
完成端口.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印
本文链接:https://www.diyifanwen.net/c1rqew0ukch8xzko047iq_8.html(转载请注明文章来源)
热门推荐
Copyright © 2012-2023 第一范文网 版权所有 免责声明 | 联系我们
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ:xxxxxx 邮箱:xxxxxx@qq.com
渝ICP备2023013149号
Top