別のスレッドからキャンセルできるようにする必要がある、実行時間の長い COM+ メソッドがあります。COM+ オブジェクトを操作するために C#/.NET を使用しています。両方の COM+ オブジェクトを「フリー」スレッド モデルを持つように構成しました。この C# サンプルは、COM+ オブジェクトの使用方法を示しています。
static void Main(string[] args)
{
var sampleCOMClass = new SampleCOMObjectClass();
var cancelToken = new CancelCOMObjectClass();
try
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(10));
cancelToken.Cancel(); // this method never makes it to COM
Console.WriteLine("Cancelled!");
});
sampleCOMClass.LongProcess(cancelToken);
}
finally
{
Marshal.ReleaseComObject(sampleCOMClass);
Marshal.ReleaseComObject(cancelToken);
}
}
私の長期実行プロセスはキャンセル トークンを正しくチェックして、処理を終了する必要があるかどうかを判断しますが、Cancel
メソッドは COM+ オブジェクトに到達しません。メソッドがブロックされているかのように、LongProcess
終了を待っています。「フリー」スレッド モデルにより、実装が同期を管理できると考えたため、なぜこれを行っているのかわかりません。
これは、再現する最小限の例を含む BitBucket リポジトリです。 https://bitbucket.org/theonlylawislove/so-blocking-com-call
Cancel
が呼び出されない/ブロックされないのはなぜですか?
COMオブジェクトのキャンセル
STDMETHODIMP CCancelCOMObject::Cancel(void)
{
_isCancelled = VARIANT_TRUE;
return S_OK;
}
STDMETHODIMP CCancelCOMObject::get_IsCancelled(VARIANT_BOOL* pVal)
{
*pVal = _isCancelled;
return S_OK;
}
サンプルCOMオブジェクト
STDMETHODIMP CSampleCOMObject::LongProcess(ICancelCOMObject* cancel)
{
VARIANT_BOOL isCancelled = VARIANT_FALSE;
while(isCancelled == VARIANT_FALSE)
{
Sleep(1000);
cancel->get_IsCancelled(&isCancelled);
}
return S_OK;
}