.net 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 {

我有一个长期运行的COM+方法,我需要能够从另一个线程取消它。我正在使用C#/.NET与COM+对象交互。我将两个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存储库,其中有一个简单的示例可供复制。

为什么
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/代码>。