WinXP pro VS2005 MFC
こんにちは。早速ですが質問です。
以下のコードを任意の場所で
{
・・・
CMyTread tread;
tread.CreateTread();
tread.CreateTread();
・・・
}
としたとき、
期待した動作はそれぞれのスレッドでコマンドプロンプトを開き
出力してほしかったのですが、結果はコマンドプロンプトが1つしか表示されず、
排他制御が無いので好き勝手に表示してしまいます。
各スレッドごとにコマンドプロンプトを表示して出力する方法を
教えてください。
また、これに関連して、stdin等の入出力はどの単位で持っているのでしょうか?
今回の件で「プロセスごと」にstdinはあって、主スレッドが各スレッドに振り分けている?
とも思ったのですが、あっていますか?
stdinに関して調べてもどうもUNIXメインでヒットし、
実体が掴めず困っています。
よろしくお願いします。
/* .h */
class CMyTread : public CObject
{
private:
CWinThread* m_phTread;
public:
CMyTread();
CWinThread* CreateTread(void);
static UINT TreadA(void*);
};
/* .cpp */
CMyTread::CMyTread() { m_phTread = NULL; }
CWinThread* CMyTread::CreateTread(void)
{
return ( m_phTread = AfxBeginThread( this->TreadA, this ) );
}
UINT CMyTread::TreadA(void* lpVoid)
{
::AllocConsole();
freopen( CON,r,stdin);
freopen( CON,w,stdout);
for(int i=0;i<10;i++)
std::cout << i << std::endl;
::FreeConsole();
return 0;
}
標準入出力もリソースのひとつであり、あくまで管理はプロセス単位です。
メインが振り分けとかそういうことでもありません。
スレッド間ではリソースが共通なので、どのスレッドから書いても同じものに書き出しをする、
スレッドとリソースの関係というのは一般にそういうものです。
# WindowsではConsoleを作成することもできますが、スレッド毎に別の窓をあけることは
# 多分できないのでは?類似のウィンドウを独自実装するなり、マルチプロセスモデルにする
# なりが現実解かと。
>Banさん
返信ありがとうございます。
なるほど。
メッセージなどと違って渡っていくのではなく、
各スレッドが直接参照しにいくものだとイメージできました。
たぶんリソースというものが不理解のせいだと思うのですが、
リソースとは、実行ファイル内にあって、
必要なときに引っ張ってくる「データ」だと思っております。
stdin等がリソースならば、それに関連付けれるコンソールは1つで
出力が一箇所にまとまってしまうのもわかるような気がします。
ただ、ダイアログ等はインスタンスとして作成されるとき
リソースを読み込んで複数展開します。
であれば、リソース単体をインスタンス化できないのはなぜなんでしょうか?
仕様といえばそれまでなんですが、
利点というか、そういう風に落ち着いている理由などあればお願いします。
もう少しお付き合いいただければ幸いです。
> メッセージなどと違って渡っていくのではなく、
> 各スレッドが直接参照しにいくものだとイメージできました。
そうですね。
> リソースとは、実行ファイル内にあって、
> 必要なときに引っ張ってくる「データ」だと思っております。
常にそうとも限らないのですが、イメージとしてはだいたいそんなものです。
> stdin等がリソースならば、それに関連付けれるコンソールは1つで
> 出力が一箇所にまとまってしまうのもわかるような気がします。
stdin自体は、FILE*型として定義済みのグローバル変数です。
そして、その接続先が(デフォルトで)コンソールになるようになってます。
# コンソールという外部リソースをファイルに見立てて、
# ファイルへのI/Oと同様にコンソールが扱えるようにしている。
# >抽象化された共通インターフェイス
> ただ、ダイアログ等はインスタンスとして作成されるとき
> リソースを読み込んで複数展開します。
外部リソース(プログラム外部の資源)というのは、OSに依存しない概念です。
Windowsの世界でいう「(リソースファイルで定義する)リソース」と、
stdinの「リソース」は、どちらもリソースではありますが、
動作/仕様などは別物であるということは把握されていますでしょうか。
ダイアログ(Windowsのリソース)と直接的に比較してもあまり意味はありません。
> であれば、リソース単体をインスタンス化できないのはなぜなんでしょうか?
> 仕様といえばそれまでなんですが、
> 利点というか、そういう風に落ち着いている理由などあればお願いします。
ダイアログの場合、リソースを読んで個別のダイアログのハンドル(HWND)を作ります。
stdinの場合、stdin自体が既にハンドル(FILE*)です。
複数のファイルが開きたければ、fopenを使えばFILE*が作れますが、
stdinを二つ作ったとしても(まぁできませんが)コンソールが二つ開いたりはしません。
# ハンドルをduplicateしても、実際のリソースはあくまで同じものですから。
ダイアログのようなGUIのイメージで言えば、「デスクトップ」などが近いでしょうか。
ダイアログのHWNDは個別に複数作れても、デスクトップのHWNDはどこから開いても同じものですし。
Windowsの中でも、GUIとCUIはSUBSYSTEMが違うので、同列に見たらダメだと思います。
CUIの世界ではコンソールウィンドウはユニークな外部リソースで、
CUIのプロセスの中から見える標準入出力というリソースは、
GUIの中から見えるデスクトップとかそういうものに相当してるとでも思ってもらえばよいのかと。
# マルチコンソールとかもないとはいいませんが、少なくともWindowsはサポートしてないのでは?
上記とは別次元の話として、
本質的に「スレッド」というのはグローバル変数やその他のりソースを共有します。
stdinもグローバル変数で実装されていますから、
どのスレッドからでも同じものを参照します。
このあたりからも、Windows標準のコンソールを分けることは
できないのではないかと思うわけです。
一方、「プロセス」は他のプロセスとグローバル変数を共有しません。
同じコンソールを共有するプロセス群は同じコンソールを使いますが、
別のコンソールを使うようにする(継承しない)ことも、
プロセス間なら指定可能だったりします。
スレッドがこうなってる理由は、プロセスとかスレッドについて調べてもらうとして、
簡単にかけばこういう利点と欠点があります。
・直接資源共有することでIPCのような手間を省ける
・コンテキストスイッチの負荷が減って切り替えが早い
・あるスレッドの状態が他スレッドに影響を及ぼしやすい(一つ死んだら全部死ぬとか)
・プログラマが注意して排他制御などをしなければならない
Ban さんの説明では触れるだけになっちゃってるが、標準入出力の本質は
「普段はコンソールだけど、操作する人の指示で違うものに差し替えることができる」
であって、必ずしも画面・キーボードではないというのが重要。
foo > result.txt と操作すれば標準出力先は画面でなく result.txt になる
foo | bar | baz と操作すれば
標準入力 標準出力
foo キーボード パイプ1
bar パイプ1 パイプ2
baz パイプ2 画面
であるわけだ。
con は標準入出力ではなく、関連付けられているコンソール (画面・キーボード)になる
UNIX で言えば /dev/tty に相当する (微妙に差異はあるが)
で Windows でコンソール画面を使いたい場合 AllocConsole という関数があるが
1プロセスにつき1つしか使えないよと書いてあるので
コンソール画面が複数個欲しいなら複数個プロセスが必要
(これだけの話なら標準入出力は無関係であり、忘れていい)
というか、スレッドもプロセスもうっちゃっといて、
「コンソールウィンドウを便利な出力画面として使うべきではない」
でカタが付く話だったりはしないだろうか(外していたら申し訳ない)。
CUIプログラムにとって、コンソールウィンドウとは、唯一の入出力機構だと思うのだけ
れど。
#昔、ログ出力ウィンドウに使おうとして挫折した経験から。
#だってウィンドウプロシージャ書かなくていいし楽なんだもん。
#printf とかそのまま使えるし。
返信ありがとうございます。
Banさん
>stdin自体は、FILE*型として定義済みのグローバル変数です。
>そして、その接続先が(デフォルトで)コンソールになるようになってます。
># コンソールという外部リソースをファイルに見立てて、
># ファイルへのI/Oと同様にコンソールが扱えるようにしている。
># >抽象化された共通インターフェイス
この話を実はうわべだけ知っていて、
かえって混乱してしまったように思います。
FILE*型→いくつも作れる→ならそれぞれに別のコンソールを・・・と
>外部リソース(プログラム外部の資源)というのは、OSに依存しない概念です。
>Windowsの世界でいう「(リソースファイルで定義する)リソース」と、
>stdinの「リソース」は、どちらもリソースではありますが、
>動作/仕様などは別物であるということは把握されていますでしょうか。
>ダイアログ(Windowsのリソース)と直接的に比較してもあまり意味はありません。
よくわかっていないようです。申し訳ありません。
ただ、今回の件で、確かにWindowsのダイアログ等のリソースは
SDKなどで組んだときのことを考えると
「ダイアログを書く(OSが描画するための)ための情報?(位置、コントロールの種類な
ど)」
であり本当の実態は別。←また誤解を招きそう
stdinのようなリソースはシステムの何かと一対一になる物として区別できそうですが
どうでしょう?
今の感覚はstdinはシステムとプログラムの間にあるドライバのような印象です。
>ダイアログの場合、リソースを読んで個別のダイアログのハンドル(HWND)を作ります。
>stdinの場合、stdin自体が既にハンドル(FILE*)です。
>複数のファイルが開きたければ、fopenを使えばFILE*が作れますが、
>stdinを二つ作ったとしても(まぁできませんが)コンソールが二つ開いたりはしません。
># ハンドルをduplicateしても、実際のリソースはあくまで同じものですから。
はじめから何のハンドルなのか固定されているのなら
なんとなくわかるような気がします。今は
const static FILE* const stdin = システムの何か
のイメージです。
>ダイアログのようなGUIのイメージで言えば、「デスクトップ」などが近いでしょうか。
>ダイアログのHWNDは個別に複数作れても、デスクトップのHWNDはどこから開いても同じ
も>のですし。
なるほど。
イメージしやすい例でした。
思っていたより特殊性が高そうです。
おかげさまでだいぶイメージが固まりました。
>tetrapod
>Ban さんの説明では触れるだけになっちゃってるが、標準入出力の本質は
>「普段はコンソールだけど、操作する人の指示で違うものに差し替えることができる」
>であって、必ずしも画面・キーボードではないというのが重要。
ありがとうございます。
パイプの例はなるほどです。
「関連付けを変えてやると出力先は変わるが出口はあくまでひとつ」
ということであっていますでしょうか?
>シャノンさん
ぐっ、まさにそれをやろうとしてました。
楽そうだなと・・・あきらめて素直にファイルに出します。
たぶん、各コンソールにstdinがあって
それを出力先として指定してやるんだと思っていたのがまりがいで、
stdinはプロセスごとにひとつで、その先は自由に帰れるが
そのプロセスにとってのコンソールというのは決まっている。
というような理解です。
間違いがあればご指摘お願いします。
最後に恥ずかしいのですが、
コンソールって何ですか?
コレまで特に意識しなかったのですが、
なんかものすごく深くと繋がってそうで・・
(コレまでは命令コマンド呼び出して実行するだけかと・・・)
もう少しよろしくお願いします。
http://ja.wikipedia.org/wiki/コンソール
うーん、この説明だけでは大型機の経験が無いとぴんと来ないかも
要するに「対話的入出力装置の1セット」がコンソール
端的にはキーボード+画面のセット
ファイルサーバ専用 UNIX ではラックマウントされた本体だけが存在する場合があり
この場合のコンソールとは
RS-232 経由で接続されたほかのマシンの端末エミュレータとか
telnet 経由で接続されたほかのマシンの端末エミュレータとか
Xserver 専用端末とか
最近利用者が増えている家庭用ルータなんかだと
http 経由で接続された web ブラウザをコンソールと呼んでもいいかもしれない
Windows 機しか知らないとキーボードと画面は1セットっきりしかないのでイメージしに
くいかもしれない
リモートデスクトップや PCanywhere もコンソールと呼んでいいのか?微妙なところ
標準入出力はパイプやリダイレクトで変更しない限り「その端末」なわけで
> そのプロセスにとってのコンソールというのは決まっている。
これは正しいと思う。
/dev/tty は常に「その端末」(windows の con は直結しているキーボード+画面なので
異なる)
foo | bar | baz とパイプでつないだ bar がパスワードをユーザに要求する場合には
標準入出力では無理なので直接 /dev/tty に訊きにいくという使い方ができる
> コンソールって何ですか?
プログラミング方面からの説明をすれば、「コンソールアプリの唯一のメインウィンド
ウ」。
で、実は GUI アプリでもこの位置づけは変わってない。
どういうことかというと、(俺は実際に GUI アプリで AllocConsole を試みたのだけれ
ど)GUI アプリでも、コンソールウィンドウを閉じられた場合、どうあがいてもプロセ
スが終了される。
コンソールアプリにとって、コンソールウィンドウが閉じられることはアプリの終了を
意味するが、何故かそれが GUI アプリにも拡大されてしまっている。
#要するに、本来の用途以外に使おうとするとすげぇ使いにくいってこと。
> リモートデスクトップや PCanywhere もコンソールと呼んでいいのか?微妙なところ
ダメ。
リモートデスクトップにおいては、端末ではなく接続先のホストを「コンソール」と呼
びます。
#PCAnyWhereはシラネ
>tetrapod
>要するに「対話的入出力装置の1セット」がコンソール
>端的にはキーボード+画面のセット
>シャノン
>プログラミング方面からの説明をすれば、「コンソールアプリの唯一のメインウィンド
ウ」。
>で、実は GUI アプリでもこの位置づけは変わってない。
>コンソールアプリにとって、コンソールウィンドウが閉じられることはアプリの終了を
>意味するが、何故かそれが GUI アプリにも拡大されてしまっている。
広義の意味でコンソールとはそのプロセスにおいて
入出力を担うもの全般。
Windowsの場合、各プロセスにおいて必ず用意されるものであり、
プロセスにとって使う使わないは別として
そのもの自体に密接にかかわるものだと理解します。
たくさんの助言ありがとうございました。