VSUG Day がまた開催されます。お申し込みは こちら から。Windows 8 & Visual Studio 2012 が目前に迫っているので、いろいろと楽しみです。うーん。時間があったら行きたいところですが、今のところ、ちょっとどうなるか不明...。

きちんと解決できたわけじゃないけど、メモ代わりに。コトの発端は、クライアントからサーバー上のファイルにアクセスするときに、えらい遅くなるケースがある、という、よくありがちな話。
そういうときは、とりあえず WinDBG を使って、アプリケーションでどんな処理が行なわれているか確認すると。見てみると、ゴニョゴニョしてる結果として、最終的に ReadFile() 関数で一バイトごとにアクセスが行なわれているわけです。そりゃ遅いわ。
ただ、どうにもそれだけの問題じゃないようで、パケットを見てみると、サーバーからの oplock break を受信した後にそういう動作になると。SMB については全然知らないので、この辺 だとかを見ながらいろいろ試したんですが、結局、設定では何ともならなそう、という結論に。アプリケーションを修正して、読み込み方法を変えれば『遅くなる』って事象も回避できたので、とりあえずはそんな感じで。
なんつーか、もやもやした感じは残りつつも、オペレーティングシステムの不具合(?) をアプリケーションで回避するのはいつものこと、ということで自分を納得させました。
ちょっとメモ。こういうときに共用体って便利だなぁって思いますよね。
#include "stdafx.h"
#include <WinSock2.h>
int _tmain(int argc, _TCHAR* argv[])
{
in_addr ia1;
in_addr ia2;
ia1.S_un.S_un_b.s_b1 = 192;
ia1.S_un.S_un_b.s_b2 = 168;
ia1.S_un.S_un_b.s_b3 = 0;
ia1.S_un.S_un_b.s_b4 = 1;
// 16820416
printf("%d\n", ia1.S_un.S_addr);
ia2.S_un.S_addr = ia1.S_un.S_addr;
// 192.168.0.1
printf("%d.%d.%d.%d\n",
ia2.S_un.S_un_b.s_b1,
ia2.S_un.S_un_b.s_b2,
ia2.S_un.S_un_b.s_b3,
ia2.S_un.S_un_b.s_b4);
return 0;
}
iPhone 対応といっても、viewport を指定したのと、css をちょっとだけ修正したくらいですが、それでも見た目的には "それなり" になるもんなんですね。
ちょっと追記。
漏れがあったので、ちょこちょこ修正。過去にさかのぼるのはアレなので、今年分くらいでいいですかね。
Linux / UNIX では、ユーザーごとの最大プロセス数とかが制限できたりしますが、Windows ではそういう設定はありません。ということで、親プロセス側で管理したり、ってのが一般的な方法になっちゃいますが、Job Object を利用した方法を試してみました。
やり方は簡単で、JOBOBJECT_BASIC_LIMIT_INFORMATION 構造体の ActiveProcessLimit メンバに Job 内のアクティブプロセスの数を指定するだけ。『アクティブプロセス』ってことで、Suspended なプロセスはどうなるの? とかって思わなくもないですが、気にしないでおきます。
例のごとく、Explorer から起動するとうまく動かないので注意が必要と。[ ファイル名を指定して実行 ] からコマンドプロンプトを立ち上げて、その中で実行すればうまく行きます。
で、自分を入れて 5 つプロセスが立ち上がっていると、それ以上は ERROR_NOT_ENOUGH_QUOTA エラーが発生して起動できなくなる、と。使いどころは...。微妙ですね。
#include "stdafx.h"
#include <windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hJob;
JOBOBJECT_BASIC_LIMIT_INFORMATION jbli;
BOOL result;
DWORD err;
STARTUPINFO si;
PROCESS_INFORMATION pi;
hJob = ::CreateJobObject(NULL, _T("MyJob"));
if (!hJob) {
_tprintf(_T("Error CreateJobObject() : 0x%x\n"),
::GetLastError());
goto fin;
}
::ZeroMemory(
&jbli,
sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION));
jbli.LimitFlags = JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
jbli.ActiveProcessLimit = 5;
result =
::SetInformationJobObject(
hJob,
JobObjectBasicLimitInformation,
&jbli,
sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION));
if (!result) {
_tprintf(_T("Error SetInformationJobObject() : 0x%x\n"),
::GetLastError());
goto fin;
}
result =
::AssignProcessToJobObject(
hJob,
::GetCurrentProcess());
if (!result) {
_tprintf(_T("Error AssignProcessToJobObject() : 0x%x\n"),
::GetLastError());
goto fin;
} else {
_tprintf(_T("Success AssignProcessToJobObject() Function.\n"));
}
for (int i = 0; i < 10; i++) {
_tprintf(_T("Hit any key to create new process #%d\n"),
i + 1);
getchar();
::ZeroMemory(&si, sizeof(STARTUPINFO));
::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
result =
::CreateProcess(
_T("C:\\Windows\\notepad.exe"),
NULL, NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi);
if (!result) {
err = ::GetLastError();
if (err == ERROR_NOT_ENOUGH_QUOTA) {
_tprintf(_T("Process limit exceeded.\n"));
} else {
_tprintf(_T("Error CreateProcess() : 0x%x\n"), err);
}
}
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
}
fin:
::CloseHandle(hJob);
return 0;
}