COM内でSleepを実行する方法

[戻る]
assemb 2004/11/15(月) 16:09:43
[OS]Windows 2000 Server SP4
[開発環境]VisualStudioProfessional v6.0 SP5

初めて投稿します。
assembと申します よろしくお願いします。

VC++6.0の ATL COMウィザートを利用してCOMサーバを作成しようとしています。
ASP(ActiveServerPage)から呼び出して、指定した待ち時間待った後で、
指定文字列をキューに溜め込むという処理を実装しようとしています。
ここで待ちを入れるために WindowsAPI の Sleep 関数を使用したCOMサーバを
テスト的に作成して、これを IIS5.0 上に作成したテスト用の aspプログラムから
呼び出したところ、Server.CreateObjectは上手く実行できるのですが、
メソッド呼出の部分で、ループした状態?になっているのか、
ブラウザにレスポンスがいっこうに返ってこない状態です。
Sleep関数は、COMサーバでは使えないのでしょうか?


ASPのソース
---
Dim xObj,rt
Set xObj = Server.CreateObject("COMTEST.ServerObj")
rt       = xObj.Wait(5)   '5秒待つ
...
Set xObj = Nothing

---


ATL のメソッド部分のソースは以下の通り
---
/////////////////////////////////////////////////////////////////////////////
// CServerObj


// 秒単位で待ちを入れる
// 引数をVariant型で受け取る
//
STDMETHODIMP CServerObj::Wait(VARIANT waitTime)
{
    // TODO: この位置にインプリメント用のコードを追加してください
    Sleep(waitTime.lVal * 1000);
    return S_OK;
}

---

どなたがご存知の方いらっしゃいましたら
ご教授ください。

suzuka 2004/11/16(火) 12:32:59
別に COM サーバーで Sleep しようと
インプロセス サーバーであれば大した問題はなさそうに思えますが、
(VC++ やスレッドに詳しくないので間違っているかもしれませんが)

Sleep はプロセス全体を停止させますけど、それはよいのですか?
IIS プロセス丸ごと止まってよいのですか?
おそらく他のセッションのリクエストも全て止まりますよ?


あと、サーバー側のメソッドの定義と呼出側の記述が
一致していないように見受けられますが、どうですか。

COM のメソッド戻り値は VBA にとっては戻り値ではないはずです。
COM エラーが発生したかどうかの判断に使われていると思います。

レジストリに登録されたタイプライブラリと
実装が一致していなくて、メソッド呼出のタイミングで
IIS プロセスが異常終了しているの可能性も否定できないと思います。

suzuka 2004/11/16(火) 12:38:33
一部訂正

IIS デフォルトのアプリケーション保護レベルでは
アプリケーションと IIS のプロセスが別のようなので
IIS 自体は止まらないかもしれないです。

ただ、アプリケーションが動作するプロセスが停止するわけですので
パフォーマンスに重大な影響が出ると思います。>Sleep の使用

assemb 2004/11/17(水) 02:20:46
suzukaさん回答ありがとうございます。

(ちなみに言語は VBA ではなくて VBScriptです。説明不足でした)

Sleepを使用してIISは分離プロセスを使用する予定でした。
確かにプロセスをとめるとパフォーマンス的に問題ありますが、
キューにデータをためるといったことをするうえでスレッドセーフな
つくりにするには仕方ないのかなぁ〜と思ったりしていました。

まだCOMやASPの経験が浅いので、お恥ずかしい話ですがそこまで
頭がついていっていないというのが本音です。。


スレッドセーフにしようとしたら、ASPの場合 Application.lock を使うようですから、
これを実行した後に、5秒まつ・・といったロジックを Sleep を使わずに実装して、
処理が終わったあとに、Unlock してやる。といった手段がいいんでしょうか。
VC++なのにASPの論議してしまって申し訳ありません。

ちょっと自分で 5秒間 待て!みたいなプログラムを書いたことがないので、
アルゴリズムが想像できません。
教えて君みたいで誠に恐縮ではございますが、、
5秒待て!のサンプルソースなどありましたら掲載して頂けませんでしょうか。

私の実力ではどうしてもループ処理でTimerから拾うといった考えしか出てきませ
ん・・。
今から過去ログを探ってみますが、ヒットしたらゴメンナサイです。

以上よろしくお願いいたします。

dairygoods 2004/11/17(水) 11:11:53
Sleepって呼び出したスレッドを停止し、
同プロセス内の他のスレッドが実行可能ならそっちに制御を譲る
のではなかったでしたっけ?

とりあえず、
waitTime.lVal==5
であることは確認できているのでしょうか?

suzuka 2004/11/17(水) 12:44:07
>同プロセス内の他のスレッドが実行可能ならそっちに制御を譲る
リファレンスの確認をしました。その通りでした。
VB が本業なもので、ウィンドウ メッセージ処理が停止する件と
混同していたようです。ご指摘感謝。

無用な混乱を招き、申し訳ありません>元質問者殿



WshShell オブジェクトが Sleep メソッドを持っています。
ドキュメントを見る限り Win32::Sleep の代替になりそうです。
これで同じ現象が起きるか確認されると良いと思います。

また、処理に時間がかかる場合、
一度「処理中です...」のような表示だけしてレスポンスを終了し、
一定時間後に meta タグとかでクライアント側から再リクエストさせるのが
常套手段です。



ちなみに ASP ではあまりスレッドは意識しないです。
開発者もスレッドという言葉すら知らない人であふれてます。

今回のケースではどのパターンか存じませんが、
一応情報を出しておきます。

(ASP でいう)同一セッション内のリクエストは
Page ディレクティブで設定を変えない限りは平行処理されず、
順次処理されるため、Session 変数の内容が矛盾することはありません。
ですのでページ間でスレッドセーフを意識する必要はなさそうです。

ただし、別セッションのリクエストは同時に処理されるため、
Application 変数などの全ユーザー共通リソースの内容を更新したい場合などは
ご存じの通り Application.Lock が必要になってきます。

assemb 2004/11/17(水) 22:31:11
皆様貴重なご意見ありがとうございます。

いささか最初の質問に不具合があったようでご迷惑をおかけして申し訳ありません。

やりたいことを整理しますが、

1)まずASPのプログラム(Webアプリ)から、サーバに処理を要求
2)サーバロジック(ASP)から、COMサーバを呼び出してデータをキューに
  突っ込みます。この際に突っ込むキューは、NTサービスアプリケーションとして
  Windows2000上に稼動しているものに突っ込みます。
   →このサーバアプリケーションは既に開発済み。
  ※なのでCOMサーバなどのWindowsアプリケーションとメールスロットやパイプ
   等で対話出来る仕組みがここで必要になりました。

3)COMサーバが応答をASPに戻して、クライアントにレスポンスを返す。

といったかんじです。


Sleepなどで待ちを入れたかったのは、厳密にいうとキューが待ちうけ状態になっていな
い場合、ループの中で一定時間待ってリトライするために使いたかったということでし
た。

コレを行うにあたって、初回投稿させて頂きましたテストコードのところでいきなりコ
ケてしまったので、ご質問させて頂きました。


いま現在Sleepに関してはとりあえずWSH等(Suzukaさんの案)で検討することで解決と
してますが、
あとは COM の処理が正しく終わって ASP に処理が戻らないという問題に直面しており
ます。

VARIANT型の使い方が間違っているのでしょうか・・・(汗)
もう少しがんばってみたいと思いますが、記述でズバリおかしいところがありましたら
ご指摘いただけませんでしょうか。。
この中に

↓↓

/////////////////////////////////////////////////////////////////////////////
// CServerObj
//
STDMETHODIMP CServerObj::Wait(VARIANT waitTime)
{
    // TODO: この位置にインプリメント用のコードを追加してください
    if (waitTime.lVal == 5)
    {
        Sleep(waitTime.lVal * 1000);
    }

    return S_OK;
}

suzuka 2004/11/18(木) 20:20:02
えーと、VC++ で COM 使ったことないので直接回答はできませんが、
原因を探るためのヒントを…

1.Sleep させなくても IIS の応答がなくなりますか?
  (単なる空メソッドの呼び出しとか)

2.VBScript 側の最低限再現させるためのコードを
  テキストファイルに記述して test.vbs のように保存して
  実行しても同様の結果になりますか?

3.VisualStudio にはコンポーネントをデバッグする機能があると思います。
  該当メソッドが呼び出されたときにブレークできるはずでが
  lVal が大きな値になっていないか確認しましたか?

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