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; }