おかげで、あなたは状態を維持するだろういくつかのオブジェクトを作成する必要があります。通常のファイル(ソケット)ハンドルなど
ファンクションsome_func()
は別のパターンを持つ必要があります。オブジェクトのメンバ関数でなければなりません。ループ内で非同期のget
を呼び出すことはできません。 get
に電話をかけた後、ただ終了する必要があります。 get
によって開始される非同期操作が完了すると、コールバックが呼び出される必要があります(失敗した場合は、非同期操作を開始するために、このコールバックをエラーコードとともに呼び出す必要があります)。コールバックでは、オブジェクトへのポインタを持ち、それを使用します - some_func()
を呼び出します。従ってsome_func()
は、前のget
の呼び出しの結果を開始する必要があります。エラーがない場合はエラーを確認し、受信したデータを処理します。オブジェクトの状態(あなたの場合はi
とq
)を調整し、必要に応じてget
に再度電話してください。
begin -> get() -> .. callback .. -> some_func() -> exit
^ ┬
└─────────────────────────────┘
(非同期読み取りファイル付き)、いくつかのデモ例
struct SOME_OBJECT
{
LARGE_INTEGER _ByteOffset;
HANDLE _hFile;
LONG _dwRef;
int _i, _q;
SOME_OBJECT()
{
_i = 0, _q = 0;
_dwRef = 1;
_ByteOffset.QuadPart = 0;
_hFile = 0;
}
void beginGet();
void DoSomething(PVOID pvData, DWORD_PTR cbData)
{
DbgPrint("DoSomething<%u,%u>(%x, %p)\n", _i, _q, cbData, pvData);
}
// some_func
void OnComplete(DWORD dwErrorCode, PVOID pvData, DWORD_PTR cbData)
{
if (dwErrorCode == NOERROR)
{
DoSomething(pvData, cbData);
if (++_q == 5)
{
_q = 0;
if (++_i == 10)
{
return ;
}
}
_ByteOffset.QuadPart += cbData;
beginGet();
}
else
{
DbgPrint("OnComplete - error=%u\n", dwErrorCode);
}
}
~SOME_OBJECT()
{
if (_hFile) CloseHandle(_hFile);
}
void AddRef() { InterlockedIncrement(&_dwRef); }
void Release() { if (!InterlockedDecrement(&_dwRef)) delete this; }
ULONG Create(PCWSTR FileName);
};
struct OPERATION_CTX : OVERLAPPED
{
SOME_OBJECT* _pObj;
BYTE _buf[];
OPERATION_CTX(SOME_OBJECT* pObj) : _pObj(pObj)
{
pObj->AddRef();
hEvent = 0;
}
~OPERATION_CTX()
{
_pObj->Release();
}
VOID CALLBACK CompletionRoutine(DWORD dwErrorCode, DWORD_PTR dwNumberOfBytesTransfered)
{
_pObj->OnComplete(dwErrorCode, _buf, dwNumberOfBytesTransfered);
delete this;
}
static VOID CALLBACK _CompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED* lpOverlapped)
{
static_cast<OPERATION_CTX*>(lpOverlapped)->CompletionRoutine(RtlNtStatusToDosError(dwErrorCode), dwNumberOfBytesTransfered);
}
void CheckResult(BOOL fOk)
{
if (!fOk)
{
ULONG dwErrorCode = GetLastError();
if (dwErrorCode != ERROR_IO_PENDING)
{
CompletionRoutine(dwErrorCode, 0);
}
}
}
void* operator new(size_t cb, size_t ex)
{
return ::operator new(cb + ex);
}
void operator delete(PVOID pv)
{
::operator delete(pv);
}
};
ULONG SOME_OBJECT::Create(PCWSTR FileName)
{
HANDLE hFile = CreateFile(FileName, FILE_READ_DATA, FILE_SHARE_READ, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
_hFile = hFile;
if (BindIoCompletionCallback(hFile, OPERATION_CTX::_CompletionRoutine, 0))
{
return NOERROR;
}
}
return GetLastError();
}
void SOME_OBJECT::beginGet()
{
const ULONG cbRead = 0x1000;
if (OPERATION_CTX* ctx = new(cbRead) OPERATION_CTX(this))
{
ctx->Offset = _ByteOffset.LowPart;
ctx->OffsetHigh = _ByteOffset.HighPart;
ctx->CheckResult(ReadFile(_hFile, ctx->_buf, cbRead, 0, ctx));
}
}
void ADemo(PCWSTR FileName)
{
if (SOME_OBJECT* pObj = new SOME_OBJECT)
{
if (!pObj->Create(FileName))
{
pObj->beginGet();
}
pObj->Release();
}
}
は何の問題あなたが解決しようとしている:?初めてコール
get
ダイレクトを必要とする - とのために、このすべてを開始しましたかリモートホストから1つのデータムをフェッチするのに時間がかかる場合は、それを速くするために何もできません。問題は、データが返されるのを待っている間、あなたのプログラムが(おそらく他のスレッドで)何をすることができるかということです。 –@jameslarge、私はちょうど 'post'リクエストを送り、' get'関数で 'InternetReadFile'を介して共振(数バイト)を読みます。それはsooo(私の場合は1秒)をしてはいけません。 –
それほど遅くはありませんが、相手側のサーバーとその間のルータを制御しないと、何もないかもしれませんそれをスピードアップすることができます。あなたはあなたの質問に '[multithreading]'タグと '' [asynchronous] 'タグを入れます。どうして?クライアントプログラムでマルチスレッドまたは非同期IOを使用してサーバーを高速化することはできませんが、どちらか一方を使用してサーバーが応答するのを待つ間にクライアントが他の処理を実行できるようにすることはできません。あなたのクライアントが待っている間に他には何ができるのですか? –