在我的代码中,我有I/O完成端口的异步I/O,对于读/写完成回调,我得到一个HANDLE(当然可以是套接字,文件句柄,命名管道等).
因此,如果在这样的例程中出现问题,我想检查错误,但是如何知道它是"网络" HANDLE(a SOCKET,所以我应该调用WSAGetLastError())还是"非网络" HANDLE(命名管道,文件等,所以我应该打电话GetLastError())?我正在使用一个简单的标志,但它的丑陋和不方便.
如果有人可以确认这WSAGetLastError()只是别名GetLastError(),我将只使用后者.
看来是这样的:
http://us.generation-nt.com/wsagetlasterror-just-an-alias-getlasterror-help-28256642.html
但有人可以证实吗?MSDN在这个主题上并不是很清楚.
使用GetLastError()而不是安全WSAGetLastError()吗?我的意思是,如果WSAGetLastError()甚至是GetLastError()Windows95 的别名,就像有人声称的那样,我可以假设它对于下一版本的Windows也是如此 - 但是我们不能在假设的事情上编写好的代码:)
正如我们从这个截图中看到的,我采取了:
http://www.picpaste.com/pics/skinned_window.1386408792.png
出于一些奇怪的原因,Windows在我的蒙皮标题栏(黄色矩形)顶部的标题栏中绘制了自己的(未设置样式)最小化/最大化/关闭按钮,如红色箭头所示.它还在这些按钮的底部绘制了一条令人烦恼的1像素大小的线条,正如您从screeenshot中看到的那样.
您可以注意到我正在为窗口蒙皮:我正在绘制自己的标题栏(黄色矩形),并调整边框(青色,品红色,红色矩形)的大小.它们现在只是矩形,但我无法理解为什么Windows在我的黄色矩形上绘制,我在非客户区绘制,只需在WM_NCPAINT发生时绘制.一切都很好,除了这个奇怪的事情.
这种情况不会一直发生,它会在使用蒙皮窗口一段时间后发生,调整大小并最大化/最小化2-3次.特别是当我在小块程序的执行某一点上单击鼠标按下鼠标栏时,会发生这种情况.事实上,我认为WM_NCHITTEST消息中的问题可能有问题,但似乎并非如此.有一些错误,可能是一些Window Style或Window Extended Style标志错了.
我无法解释这一点,我正确地重新实现WM_NCPAINT消息(我猜),所以Windows不应该理解我正在绘制自己的标题栏吗?为什么要覆盖我的图纸?!这是Windows XP的错误吗?它似乎不会发生在Windows 7中,但我不太确定.
也许我只是错过了为此重新实现WM_*消息.有人可以帮帮我吗?这让我疯了!
注意:我不能使用WinForms,Qt或其他一些有助于为窗口设置外观的库,这是一个旧项目,所有这些都必须直接在winapi中完成,处理正确的WM_*消息.没有图书馆可以链接.
注意2:在WM_NCACTIVATE消息中使用SetWindowPos或RedrawWindow会产生相同的结果.
这是代码:
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
char szClassName[ ] = "SkinTest";
int left_off;
int right_off;
int top_off;
int bottom_off;
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the …Run Code Online (Sandbox Code Playgroud) Windows 8.1/Server 2012RC2 刚刚引入了用于虚拟内存管理的新 API:OfferVirtualMemory()、ReclaimVirtualMemory()、DiscardVirtualMemory(),它们的用法非常简单,只需查看它们的名称即可。
我不明白的是这些 API 如何与VirtualAlloc()标志MEM_RESET和一起工作MEM_RESET_UNDO,以及有哪些细微的区别。
对于OfferVirtualMemory(),MSDN 表示它与VirtualAlloc()+非常相似MEM_RESET,只不过它从工作集中删除页面,并限制对页面的进一步访问。
因此,基本上它限制了对页面的访问,如果我想再次访问这些页面,我必须调用ReclaimVirtualMemory(). 这很好,但不应该MEM_RESET也从工作集中删除页面吗?不应该MEM_RESET充当 POSIXMADV_DONTNEED标志,madvise(2)它基本上从进程的页表中删除页面,如果我将来再次访问这些页面,访问将生成软故障,并且这些页面将再次重新分配,初始化为零。
当然,如果这是真的,页面将从进程的工作集中删除,因为它们基本上被释放,即使进程保留分配的虚拟地址,并看到它们“已提交”。
现在,让我们看看DiscardVirtualMemory():这里 MSDN 没有提到任何关于MEM_RESETflag 的内容,但是如果我阅读了这个 API 的描述,它似乎与+确实是一样的。VirtualAlloc()MEM_RESET
那么,有谁知道这些 API 之间是否存在一些差异,以及这些细微差异的正确用例是什么?如果他们引入了像 一样的全新 API DiscardVirtualMemory(),那么与旧方法应该会有一些区别。
如果我想从 POSIX 移植一个使用madvise(2)和 的MADV_DONTNEED应用程序MADV_WILLNEED,模仿这种 POSIX 行为的最佳方法是什么?到目前为止,我使用VirtualAlloc()+ MEM_RESETforMADV_DONTNEED …
我正在使用GetQueuedCompletionStatusEx()API,我刚刚意识到它确实可以在 1 个系统调用中读取 N 个 OVERLAPPED 数据包,而不是像 那样只能读取 1 个 OVERLAPPED 数据包,GetQueuedCompletionStatus()但我担心的是我无法知道有关每个 OVERLAPPED 错误代码的任何信息。
虽然GetQueuedCompletionStatus()每次调用仅返回 1 个 OVERLAPPED,但它使我能够通过调用 来检查GetLastError()当前 OVERLAPPED 数据包的最后一个错误。
我怎样才能做到这一点,GetQueuedCompletionStatusEx()实际上返回 N 个重叠数据包,但不返回 N 个错误代码?
我已经阅读过通过调用GetOverlappedResult()您可以实现这一点,但我的观点是:如果我调用GetQueuedCompletionStatusEx()以获取 N 个重叠数据包,然后我必须为每个数据包调用另一个系统调用,则调用 1 个系统调用以获取 N 个重叠数据包的好处是毫无意义,因为你将调用 1+N 系统调用。此时,我可以简单地保留GetQueuedCompletionStatus()并仅调用 N 个系统调用(对于 N 个重叠),而不是 1+N。
有人知道更多吗?
首先,我非常清楚如何VirtualAlloc()工作:当我保留内存块时,我得到与 64K 边界对齐的地址(可以通过 轻松获得该值GetSystemInfo()),然后当我提交页面时,我得到它们的页面大小边界,通常为 4K。
我无法得到的事情是,为什么如果我使用标志调用VirtualAlloc()(MEM_RESERVE所以我要保留页面)并且指定一定的大小,比如说 4096,那么我将无法将该区域进一步增长到 64K ?
我的意思是:当我提交页面时,我可以使用最多 4K 的内存,因为 Windows 会将这些提交与页面大小对齐(当然,我正在提交页面!),但是当我保留内存区域时,应该Windows 不会将我传递到的区域大小调整VirtualAlloc()为 64K 吗?“浪费”的 15 页都去哪儿了?
因此,如果我保留 4096 字节,我是否应该能够提交更多页面直到 65536 字节?看来并非如此,因为如果我尝试这样做,VirtualAlloc()则会因ERROR_INVALID_ADDRESS最后一个错误代码而失败。
但为什么?如果 Windows 确实在 64K 边界上保留页面,并且我保留小于该大小的页面,我会永远丢失不保留的页面吗?因为似乎没有办法再次提交它们,或者调整区域大小以适应我因较低的预留而错过的 64K 边界。
那么,进程的虚拟空间会不会有漏洞呢?为了避免这种情况,我是否必须始终在 64K 边界上保留内存,因此在保留页面时始终VirtualAlloc()给出64K 对齐的值?
当我使用的时候呢MEM_RESERVE|MEM_COMMIT?由于标志的原因,我不应该在那里传递 64K 对齐的大小吗MEM_RESERVE?
我提供了一些我尝试过的代码示例。正如您在这里所看到的,第一个函数成功了,因为我保留了更多页面,那么我的提交将有足够的“保留区域”来实际提交,但在这种情况下,该区域将<64K,那么那些“丢失的”页面去哪儿了?
在第二种情况下,我只是MEM_RESERVE|MEM_COMMIT,因此提交其他页面会失败并显示ERROR_INVALID_ADDRESS最后一个错误代码。很公平,但同样在这里,为什么我不能提交更多页面,至少在 64K 边界上?为了不浪费地址并创建这些“漏洞”,我真的应该在 64K 边界上保留虚拟内存吗?如果我不遵守这个原则怎么办?我总是看到很多代码只是简单地VirtualAlloc()用MEM_COMMIT|MEM_RESERVE …
我正在使用完成端口在Windows NT中编写tcp服务器以利用异步I/O. 我有一个TcpSocket类,一个TcpServer类和一些(虚函数)回调在I/O操作完成时调用,例如onRead()用于读取完成时.我在建立连接时也有onOpen(),在连接关闭时也有onEof(),依此类推.我总是有套接字的挂起读取,所以如果套接字有效地获取数据(读取将完成大小> 0)它调用onRead(),而不是客户端从客户端关闭套接字(读取将是完成大小== 0)它调用onEof(),服务器知道客户端何时用closesocket(server_socket)关闭套接字; 从它的角度来看.
一切都优雅,但我注意到了一件事:
当我调用closesocket(client_socket); 在连接的服务器端端点,而不是客户端端(设置为linger {true,0}或不设置),挂起的读取将完成为错误,即读取大小不仅是== 0,但GetLastError()也返回错误:64,或'ERROR_NETNAME_DELETED'.我在网上搜索了很多这个,但没有发现任何有趣的东西.
然后我问自己:但这是一个真正的错误吗?我的意思是,这真的可以被视为错误吗?
问题是在服务器端,当我关闭socket(client_socket)时,将调用onError()回调; 而不是onEof().所以我想这个:
如果我收到此'ERROR_NETNAME_DELETED'"错误",请调用onEof()而不是onError()?会引入一些错误或未定义的行为吗?让我问这个问题的另一个重点是:
当我通过'ERROR_NETNAME_DELETED'收到此读取完成时,我检查了OVERLAPPED结构,特别是包含底层驱动程序的NTSTATUS错误代码的overlapped-> Internal参数.如果我们看到一个NTSTATUS错误代码列表[ http://www.tenox.tc/links/ntstatus.html ],我们可以清楚地看到'ERROR_NETNAME_DELETED'是由NTSTATUS 0xC000013B生成的,这是一个错误,但它是称为"STATUS_LOCAL_DISCONNECT".好吧,它看起来不像是错误的名称.看起来更像是"ERROR_IO_PENDING"这是一个错误,但也是一个正确行为的状态.
那么检查OVERLAPPED结构的Internal参数怎么样呢?当这是==到'STATUS_LOCAL_DISCONNECT'时,会执行对onEof()回调的调用?会弄得一团糟吗?
另外,我必须说,从服务器端,如果我在调用closesocket(client_socket)之前调用DisconnectEx(); 我不会收到那个错误.但是我不想叫DisconnectEx()呢?例如,当服务器关闭并且不想等待所有DisconnectEx()完成时,但只想关闭所有客户端的连接.
我有经典的 IOCP 回调,它使 i/o 待处理请求出队、处理它们并取消分配它们,如下所示:
struct MyIoRequest { OVERLAPPED o; /* ... other params ... */ };
bool is_iocp_active = true;
DWORD WINAPI WorkerProc(LPVOID lpParam)
{
ULONG_PTR dwKey;
DWORD dwTrans;
LPOVERLAPPED io_req;
while(is_iocp_active)
{
GetQueuedCompletionStatus((HANDLE)lpParam, &dwTrans, &dwKey, (LPOVERLAPPED*)&io_req, WSA_INFINITE);
// NOTE, i could use GetQueuedCompletionStatusEx() here ^ and set it in the
// alertable state TRUE, so i can wake up the thread with an ACP request from another thread!
printf("dequeued an i/o request\n");
// [ process i/o request ] …Run Code Online (Sandbox Code Playgroud) 首先,让我说我非常了解VirtualAlloc()现代操作系统的虚拟内存设施是如何工作的,一般来说是如何工作的。
说,使用Windows API的MAP_RESERVE标志VirtualAlloc(),不使用也MEM_COMMIT,今天有一些实际用途吗?
我的意思是,当我打电话VirtualAlloc()跟MEM_RESERVE|MEM_COMMMIT我都保存和提交页面,但我知道,操作系统将真正分配页面,只有当我尝试写放进去。这种优化几乎发生在所有现代操作系统上。
因此,这种优化的头脑,如果我叫VirtualAlloc()用MEM_RESERVE,然后我把它叫做几次MEM_COMMIT提交页面,是不是同一调用的结果VirtualAlloc()只有一次,指定MEM_RESERVE|MEM_COMMIT?
既然指定只MEM_RESERVE保留页边界地址,不提交真实页,那么MEM_RESERVE|MEM_COMMIT只保留+提交我写的页,不是MEM_RESERVE单独使用,今天浪费时间吗?由于只有1呼吁VirtualAlloc()与MEM_RESERVE|MEM_COMMIT我基本上能获得调用的结果相同VirtualAlloc()1周时间MEM_RESERVE,并调用了好N倍MEM_COMMIT。
作为我所说的证据,我注意到MEM_RESERVE在使用mmap(2)系统调用的Unices/POSIX 系统中根本不存在该工具。此外,您可以在那里“提交”一大块页面调用mmap(2)一次,然后只有在您写入页面时才会真正分配页面,所有页面均由操作系统优化。
那么,MEM_RESERVE只有当内存页是一种宝贵的资源时,单独使用只是过去的事情才有用,所以今天没有用吗?或者,单独使用这个标志(然后用 调用VirtualAlloc()N 次MEM_COMMIT)仍然有一些我缺少的实际用途?
我正在尝试从此处获取的配对堆的C ++实现:http : //home.fnal.gov/~stoughto/build/graphviz-2.22.2/lib/vpsc/pairingheap/PairingHeap.h http ://home.fnal.gov/~stoughto/build/graphviz-2.22.2/lib/vpsc/pairingheap/PairingHeap.cpp
我将PairingHeap与std :: priority_queue进行了比较,结果如下:
gcc 4.7 -O3,核心i7 2.4Ghz rdstc指令来测量周期
-------------------------------------------------------------------------------
for 100.000 elements:
o std::priority_queue<int>
- insert: 9,800,415 cycles
- extract: 29,712,818 cycles
- total: 39,513,233 cycles [0.031secs]
o PairingHeap<int>
- insert: 34,381,467 cycles
- extract: 259,986,113 cycles
- total: 294,367,580 cycles [0.125secs]
-------------------------------------------------------------------------------
for 1.000.000 elements:
o std::priority_queue<int>
- insert: 95,954,533 cycles
- extract: 518,546,747 cycles
- total: 614,501,280 cycles [0.296secs]
o PairingHeap<int>
- insert: 344,453,782 cycles
- extract: 3,856,344,199 cycles
- total: …Run Code Online (Sandbox Code Playgroud) c++ performance performance-testing data-structures cpu-cache
winapi ×7
c++ ×4
windows ×4
iocp ×3
c ×2
allocation ×1
cpu-cache ×1
io ×1
memory ×1
networking ×1
performance ×1
posix ×1
skins ×1
tcp ×1
windows-8.1 ×1