関数が複数から呼ばれた場合

[戻る]
nonta 2005/07/29(金) 00:48:44
C/C++の基本的な事かもしれませんが教えてください。
例えば指定されたファイルを開いてデータを読む関数があります。
1つ目のファイルをメニューから「開く」でこの関数を呼びます。
ここで読み込ませたファイルが巨大で読み込みに凄く時間がかかるとします。
その間に2つ目のファイルを「開く」でこの関数を呼んだ場合、
動作ってどうなりますか?
この関数の引数にファイル名がある場合や当然ファイルポインタも
ありますが、1つめのファイルを読んでる間に、2つ目のファイルの
ものに書き換えられてしまうのでしょうか?不思議です。
宜しくお願いします。

シャノン 2005/07/29(金) 02:36:35
一つ目のファイルの読み込みが終わらなくても、読み込み関数は制御を戻してしまうの
ですか? まぁ確かに、巨大なファイルを非同期で読み込むのは考えられることです
が。
その非同期読み込み関数がスレッドとして動いているならば、2つの異なるスレッドか
ら同じ関数を呼んでも、スレッドごとに独自のスタック空間を持っているので、バッテ
ィングすることはありません。
ただし、その関数内の static 変数や、関数外のグローバル変数などは共有されるた
め、そういったものをブチ壊さないように、排他が必要になるでしょう。

nonta 2005/07/29(金) 10:03:54
>一つ目のファイルの読み込みが終わらなくても、
>読み込み関数は制御を戻してしまうのですか?

非同期ではなく、普通に読んだ場合です。
ファイルを読んでる最中(読み込み関数が動作している)は、
他からはその関数呼べないのでしょうか?
呼んだ場合にはどうなるのでしょうか?
スレッドとかは考えていません。
例えば、ドラッグ&ドロップとかで複数ファイルを読み込ませる(方法はわかりませんが)
場合は、どうなってるのでしょうか?
ファイル名はすぐわかりそうなもんなんで、1つ目のファイルを読んでる間に
2つ目のファイルを開こうとする場合です。

1つ目のファイルが読み込み完了して関数が復帰するまで
2つ目のファイルは待っているのでしょうか?

. 2005/07/29(金) 10:08:45
> ファイルを読んでる最中(読み込み関数が動作している)は、
> 他からはその関数呼べないのでしょうか?
呼べない。
ファイル読込関数をどっかで呼んでいるとそれがおわるまで先に進めないから。

呼び出し先
{
    ファイル読込関数呼び出し(ファイルA)
    /* ファイル読込関数がおわるまで先に進まない */
    ファイル読込関数呼び出し(ファイルB)
}

tetrapod 2005/07/29(金) 10:25:51
呼べないというより、呼ばれないというべきか。呼ばれる経路が無いというべきか。

CHogeDlg::OnReadButton() {
  ファイル読み込み(ファイル1);
  // A 地点
  ファイル読み込み(ファイル2);
}
とかなっていれば、ファイル1が読み込み完了するまでA地点に帰ってくることは無いし
ファイル2が読み込み完了する=OnReadButton() 終了まで CHogeDlg を操作することはでき
ない。
メッセージループが回ってないから。
ユーザが操作してもファイル読み込み完了まで CHogeDlg は応答しない。
すなわち OnReadButton() が処理中に2重に呼ばれることはない。

# マルチスレッドとか自前メッセージループとか使えば、
# 呼ばれるように組むこともできますが、そうではないという前提。

それ(応答しない)では操作性が悪い、ということならそれなりの対処が必要。

nonta 2005/07/29(金) 11:02:39
>CHogeDlg::OnReadButton() {
>  ファイル読み込み(ファイル1);
>  // A 地点
>  ファイル読み込み(ファイル2);
>}

これだと、確かにファイル2は呼べませんが、
上にも書いたドロップの話だとどうなりますか?
ドロップっていつでも出来ますけど・・・。

CHogeDlg::ドロップ() {
   ファイル読み込み();
}

で、画面上からイベント(?)でドロップが呼ばれますよね?
これってドロップ出来なくなっちゃうんでしょうか?
それだと困るので、ドロップはいくらでも出来て(と言っても限界はあるでしょうが)
ファイルの読み込みがおっつかないときは、裏で待ってる(?)みたいな
処理ってどうすれば良いのでしょうか?
ちとイベントの事調べて見ましたがSendMessageとかPostMessageって
使えば、1つめのファイル読み込みを気にせず2つ目3つ目とドロップ
できますか?

. 2005/07/29(金) 11:04:49
> SendMessageとかPostMessage
使っている時点でスレッドで動いているのでは?

>> スレッドとかは考えていません。

nonta 2005/07/29(金) 11:18:24
>使っている時点でスレッドで動いているのでは?

いえ。上の話から推測すると、
「ドロップ()」の処理でファイル読み込みをしている場合は、
次のファイルがドロップ出来ないという事になりませんか?

と、なると

CHogeDlg::ドロップ() {
   PostMessage(ファイル読み込み()に行け);
}

CHogeDlg::ファイル読み込み(){
   読め読め読め読め読め;
}

作るべきなのかな?と思ったわけです。
PostMessageのヘルプ見ると「対応するスレッドがメッセージを処理するのを
待たずに制御を返します。」とありました。
スレッドは自分自身(メインスレッドと呼べばいいですか?)でいいのかな?と。

同一スレッド内で、SendMessageとかPostMessageって使わないものですか?
概念的な話を聞きたかったのですが、流れで作りの話にまでなってしまって
すいません。

tetrapod 2005/07/29(金) 11:40:26
>「ドロップ()」の処理でファイル読み込みをしている場合は、
>次のファイルがドロップ出来ないという事になりませんか?
そのとおりです。
CHogeDlg::OnDrop(CString ファイル名) { 読み込み(ファイル名); }
とすると、読み込みが終了するまで CHogeDlg のメッセージループは回りません。
つまり、読み込み完了まで CHogeDlg の動作は停止し、その間 Drop を受け付けません。

>CHogeDlg::ドロップ() {
>   PostMessage(ファイル読み込み()に行け);
>}
PostMessage が何をするかを考えれば動作が判ります。
PostMessage は「メッセージを積む」だけです。
詰まれたメッセージは、メッセージループが動作しているときに処理されます。

ChogeDlg::Onファイル読み込みメッセージ() {
  読み込み(メッセージ中のファイル名);
}
単にこれだけなら、この処理中にメッセージループが回らないわけで、
ユーザから見た結果は同じです

だから
>それ(応答しない)では操作性が悪い、ということならそれなりの対処が必要。
と書いたわけで、「それなりの対処」とは
・マルチスレッド化して、ファイル読み込みはUIスレッドとは別に実施
・ファイル読み込み処理中にメッセージループをまわす
・あるいはもっと他の何か
ということになります。

fred 2005/07/29(金) 11:52:03
> CHogeDlg::ドロップ() {
>    PostMessage(ファイル読み込み()に行け);
> }
>
> CHogeDlg::ファイル読み込み(){
>   読め読め読め読め読め;
> }

1回目のドロップで "ファイル読み込み()" を実行している最中は、
ユーザーがファイルをドロップしても "ドロップ()" は呼ばれません。

nonta 2005/07/29(金) 12:42:03
[[解決]]
>単にこれだけなら、この処理中にメッセージループが回らないわけで、
>ユーザから見た結果は同じです
なるほど。良く分かりました。

>・ファイル読み込み処理中にメッセージループをまわす
これ簡単に出来るのでしょうか?
やり方教えて頂けるとありがたいです。


一応本題は理解出来たので、「解決」とします。
ありがとうございました。

Geo=TK3 2005/07/29(金) 13:53:16
>これ簡単に出来るのでしょうか?
>やり方教えて頂けるとありがたいです。

 例えばこんな感じでしょうか。
 
  CHogeDlg::ファイル読み込み(){
    一時バッファ (サイズは適当) 用意;
   while (ファイル読み込みが完了していない間) {
      一時バッファにファイル読み込み (上記で用意したサイズ分だけ読む) ;
      メッセージ処理;
    }
  }

  要するにメッセージループの中にファイルの一部を読み込む処理を入れる訳です。
 ただしこの例では CHogeDlg::ファイル読み込み関数の実行中に再度 CHogeDlg::ファ
イル読み込み関数が呼び出された場合など、考慮してない部分が多々ありますのでご注
意ください。

超初心者 2005/07/30(土) 02:30:34
メッセージループをまわすってことは
再入可能(リエントラント)とかあるし
ドロップ処理中にメニュー操作とか終了処理も出来てしまうことになる。
とはいうものの、楽な方法は無いな。

ドロップ処理では排他的ファイルオープンだけしておいて、直ぐにリターンする。
取りあえず今すぐ必要な処理だけして、
その後も必要になるたびに必要な部分だけのファイル読み込みをする
ことでドロップ処理を軽くする。など

あるいは素直に、
重い処理のときは、同時に複数のファイルを開けないほうがいい。
スラッシングがおきてもっと遅くなるよ。

古いスレッドには追加発言できません。