.net COM+;长时间运行的方法导致其他方法阻塞/挂起
我有一个长期运行的COM+方法,我需要能够从另一个线程取消它。我正在使用C#/.NET与COM+对象交互。我将两个COM+对象配置为具有“自由”线程模型。这个C#示例演示了我打算如何使用COM+对象.net COM+;长时间运行的方法导致其他方法阻塞/挂起,.net,multithreading,com,apartments,.net,Multithreading,Com,Apartments,我有一个长期运行的COM+方法,我需要能够从另一个线程取消它。我正在使用C#/.NET与COM+对象交互。我将两个COM+对象配置为具有“自由”线程模型。这个C#示例演示了我打算如何使用COM+对象 static void Main(string[] args) { var sampleCOMClass = new SampleCOMObjectClass(); var cancelToken = new CancelCOMObjectClass(); try {
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存储库,其中有一个简单的示例可供复制。
为什么Cancel
从未被呼叫/阻止?
取消对象
STDMETHODIMP CCancelCOMObject::Cancel(void)
{
_isCancelled = VARIANT_TRUE;
return S_OK;
}
STDMETHODIMP CCancelCOMObject::get_IsCancelled(VARIANT_BOOL* pVal)
{
*pVal = _isCancelled;
return S_OK;
}
STDMETHODIMP CSampleCOMObject::LongProcess(ICancelCOMObject* cancel)
{
VARIANT_BOOL isCancelled = VARIANT_FALSE;
while(isCancelled == VARIANT_FALSE)
{
Sleep(1000);
cancel->get_IsCancelled(&isCancelled);
}
return S_OK;
}
样本对象
STDMETHODIMP CCancelCOMObject::Cancel(void)
{
_isCancelled = VARIANT_TRUE;
return S_OK;
}
STDMETHODIMP CCancelCOMObject::get_IsCancelled(VARIANT_BOOL* pVal)
{
*pVal = _isCancelled;
return S_OK;
}
STDMETHODIMP CSampleCOMObject::LongProcess(ICancelCOMObject* cancel)
{
VARIANT_BOOL isCancelled = VARIANT_FALSE;
while(isCancelled == VARIANT_FALSE)
{
Sleep(1000);
cancel->get_IsCancelled(&isCancelled);
}
return S_OK;
}
原来我的COM+exe有这个
#define _ATL_APARTMENT_THREADED
去掉它解决了我的问题
奇怪的是,ATL Simple Object向导在指定“自由”线程模型时没有提到/修改这一点
很高兴知道是谁投票结束了这个问题。它非常有效。您是否尝试过将COM对象标记为
两者
而不是自由
?事实上,如果您遵循所有规则,中性
将更合适:我只是使用“中性”线程模型删除并重新添加了对象,结果相同。有没有可能.NET不是自由/中立的模型?您不需要使用CoInitializeX(而不是CoInitialize)创建对象吗?.NET内部使用哪一个。显然isCancelled与_isCancelled不是同一个变量。您永远无法访问IsCancell,它是该方法的局部变量。您认为使用两个不同的COM对象是一个好主意,这让您的脚受伤。事实并非如此,除非您给它一个引用,否则不可能找到另一个。正确,\u isCancelled在cancel-token-COM对象中。公共getter检索该值并将其设置为LongProcess中的局部变量(isCancelled)。while循环保持使用cancel COM对象中的局部变量设置局部变量。最好使用CComObjectRootEx
而不是CComObjectRoot
来显式指定线程模型,而不依赖于该宏。NET为我处理COM对象的创建。有没有一种方法可以让我在.NET中指定用“Ex”创建它?这个宏与.NET如何创建COM对象无关。它影响ATL如何为COM对象的线程模型实现管道。在C++代码中使用<代码> CCOMObjeTrutoTeX/代码>。