Slim Reader Writer ロック

WindowsのWin32APIの話、実験してないので予想で記述。

Vistaから使える

Vistaから使える。

クリティカルセクションに比べて早い

クリティカルセクションはリーダーとかライターの区別がないので、リーダーがたくさん動いていると大変になる場合がある。

ShareモードとExclusiveモードがある

同じロックに対してSharedモードで取得するかExclusiveモードで取得するか選択できる。Shareモードをロックした場合は次のShareモードロックも取得できるはず。Exclusiveはロックが全くない場合だけ取得できるはず。Exclusiveがロックされているときはどっちも取得できない。

再取得できない

クリティカルセクションは取得後に再取得できたがこれはできないらしい。小さなコードブロックで使いデッドロックしないように注意。

使い方

  • InitializeSRWLockで初期化、またはSRWLOCK_INITを直接設定
  • AcquireSRWLockSharedでShareモードロックを取得、ReleaseSRWLockSharedで開放
  • AcquireSRWLockExclusiveでExclusiveモードロックを取得、ReleaseSRWLockExclusiveで開放

 

 

 

ロケール ACP コンソール

ReadFile

コンソール含めたファイルから読み込むには最終的にAPIのReadFileを呼ぶ。

入力元がコンソールの場合、この関数は改行すると制御が返る。EOFはここでは普通の文字として扱われ特別な処理はない。入力元がファイルの場合は終わりに達すると単にdwReadが0になる。

ここでコンソールに日本語を入力した時の文字コードはGetACP()と同じと思われ、レジストリHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACPの値、この値はコントロールパネルの地域と言語の設定の非ユニコードアプリの設定になると思われる。この値の変更はシステム再起動が必要。

SetConsoleCP()を使えばプロセスの入力コードページを変えられるが、CP_UTF8を設定してReadFileを呼んでもうまく読み込めない。IMEが起動しなくなりコピペで入力してもdwRead=0が返る(XPの場合)。

ReadFile()は汎用の入力APIだがコンソール用のReadConsole()がある。引数はReadFile()と大体同じだが、レファレンスによるとこの関数を使えばユニコードを読めると書いてある。そしてこの関数はAnsiとUnicodeで関数がわかれている。ReadConsoleW()を呼べばユニコード入力を受け取れる。

出力も同様にSetConsoleOutputCP(), WriteConsole()などでできると思う。

標準ライブラリ

上記はAPIレベルの話だったが、C標準ライブラリでは入力元がファイルだろうがコンソールだろうが同様に扱うので最終的にReadFile()を呼ぶ。よってコンソールからのユニコード入力はできないと思われる。

このコードはコンソールからReadFile()読んだデータをユニコードに変換して返す。変換のはロケールにしたがって動くのでデフォルトのCロケールだと日本語すらちゃんと変換できない。

こう書くとロケールのコードページ932が指定されユニコードに変換されるので日本語は入力できるが中国語などは入力できないしここでロケールを中国語に変えても元々が932で読み込んでるので正しく変換できないだろう。

_setmode()関数の引数にユニコード関係も追加されたがこれらは入力がファイルの場合には機能するがコンソールの場合はうまくいかないだろう。

コンソールからの入力は上記のように大変だが出力はWriteFile()でもうまく動くとの報告もあるが調べてない。

win32 Windowsが64ビットか調べる

http://stackoverflow.com/questions/336633/how-to-detect-windows-64-bit-platform-with-net

その他、CPUとプロセスが64ビットか調べる

AMD64でしか実験してない。ARMやIA64ではどうなるのか不明。

文字コード覚書

文字コードの話は正確にやろうとすると大変なので適当に書いてみる。

文字集合:文字を集めたもの

JIS X 0208
Unicode

符号化方式:文字集合に番号をつけたもの

ISO-2022-JP
EUC-JP
Shift_JIS

コードセット

文字集合の集合、EUC-JPではASCII+JIS X 0208+その他

実際の文字コード:1バイト

US-ASCII:0から127まで使う標準的な半角英数文字と制御コード

128から255までをどう使うかでいくつかの文字コードがある

ISO-8859-1はドイツ語のウムラウトとかアルファベットの上に何らかのマークがつく文字を収録していてヨーロッパでは基本の文字コード、WindowsではWindows-1252ともいわれる。

ISO-8859-5はキリル語(ロシア語)の文字だがあんまり使われずKOI8-Rが使われるらしい。

実際の文字コード:2バイト以上

欧米件は文字数が少ないので1バイトでよかったが、漢字圏では足りないので2バイト以上になる。

Shitf-JIS:最大2バイト

もともと日本語はJIS X 0201でASCIIでつかってなかった領域にカタカナを収めて1バイトで使っていた。

漢字が表示できるようになってからは、この1バイトの使ってない領域を2バイト文字へ移行する制御コードとして使い、2バイトを利用して漢字を表現していた。

Cプログラムなどで問題になるのは2バイト文字の2バイト目が\などになった場合である。例えばパスを¥で区切るプログラムを単純に作っているとこの2バイト目の¥に引っかかっておかしくなってしまう。

EUC-JPやUTF8では2バイト目以降のバイトにこれらのASCIIは入らないのでこのような問題は起こらない。

ソフト業界が国際化してからはWindowsではUTF16を使いLinuxではUTF8を使うことが多い。UTF16は基本的に2バイト固定なので文字操作はしやすいが欧州圏からみるとメモリがもったいない。

Unicodeでは¥とバックスラッシュは区別されているが、JIS X 0201のASCII部分も実は若干変わっていてバックスラッシュのところに¥を割り当てている。文字コード変換などでShift-JISからUnicodeに変換したときもし¥がそのままUnicodeの¥になってしまうと困るので運用上はASCII部分は変換しない慣習になっている。逆にUNICODEの\(U+00A5)からShift-JISに変換した場合はバックスラッシュに変換してしまう。よってさらにこれをUNICODEに変換したら元の文字列と同じにならないことになる。日本語環境では今後もバックスラッシュにお目にかかることはないのだろう。

UTF8で書いていて本当にバックスラッシュを表示したい場合はHTMLなら

と書けばいいようだ。実際書いてみる→\

Windowsでのプログラム

Windowsでは文字コードをコードページという言い方をしているようだ。

MultiByteというのは日本語環境ならShift-JISというように、Unicode以前の2バイト以上文字列のことでWindows98とかのころのOSのデフォルトの文字コードのことだろう。

WideChar、ワイド文字とはUTF16をさす。

第一引数のCodePageは入力文字列のコードページだがCP_ACPを指定すればOSのデフォルト設定が使われ日本語WindowsならShift-JIS(codepage932)になると思われる。もっとも昨今のWindowsはこのデフォルトのコードページを変えられると思われそれは、言語設定の非UNICODEアプリの設定になると思われる。

ロケールとの関係

Cライブラリにはmbstowcsがあり、これで変換できる、LC_CTYPEがマルチバイト文字列をあらわしている。

コンパイラ

最近のコンパイラはUNICODEで保存されていてもOKなのでリテラル文字列を国際化できる。一般にはコードはASCIIのみがよいとされているものと思われるが。

VC2008ではファイルの保存で文字コードを選択できるので以下のようなコードが書ける。

XPでの実行結果

xpi18nmessage

Windows8での実行結果

8int18

コンソールで表示

wprintf()などで上のプログラムの文字列を表示しようとしてもほとんど表示できない。CRTは内部でマルチバイトにしてしまうためだとおもわれる。

以下のように強引に書いてもマルチバイトとして表示してしまう。

もともとコンソールはワイド文字仕様になっていないものと思われる。

Ubuntuのコンソールで実験

gccで上のプログラムを普通にコンパイルしても–input-charset=utf8 –exec-charset=utf8などのオプションをつけても以下のようにちゃんと表示されなかった。catなどではちゃんとutf8ファイルを表示出きるのでできると思うがいまはスルー。

システムファイルが邪魔でデフラグできないのでUSNを消してみた

大きいファイルをデフラグしようと思ったら、システムファイルらしきものがポツポツとあって、これが邪魔で完全にデフラグできない。

このシステムファイルを調べてみると、C:\$Extend\$UsnJrnl みたいなファイルでこれはNTFS change journalといって、ファイルの変更を簡単に検知するための仕組みでそのためのファイルのようだ。これを消すには fsutil というコマンドでできるみたいなのでやってみた。(Windows XP)

この作業は危険だと思われるので大切なデータがあるときはやらないで
まず現在の状況を確認(Zドライブの)

消す(無効にする)。/nオプションだと作業が完了するまで待つのだと思う。/dだとすぐ帰ってくるのだと思う。この作業は1分くらいかかった。

消えたか確認

ここでデフラグする。
デフラグが終わったらもう一回つくる。

つくれたか確認