检测Thread内的布尔值更改

时间:2014-06-27 16:40:55

标签: c# c++ multithreading

我有一个c ++ dll函数,我想在C#线程中运行。

有些时候我需要取消该线程,这就是问题所在:

Thread.Abort()在我读过的众多文章中都是邪恶的 主题

唯一的方法是使用bool并定期检查它的值。

我的问题是,即使我将此值设置为true,它也没有改变,在c ++代码中仍然等于false。但是,当我显示MessageBox时,该值已更改并且工作正常。 任何想法为什么只有在MessageBox显示时才更改该值,请告诉我如何解决该问题。 C#

 public void AbortMesh()
        { 
            if (currMeshStruct.Value.MeshThread != null && currMeshStruct.Value.MeshThread.IsAlive)
            {
             //here is my c++ Object and cancel mesh used to set bool to true;                   
             MeshCreator.CancelMesh();
            }
        }

C ++

STDMETHODIMP MeshCreator::CancelMesh(void)
{
    this->m_StopMesh = TRUE;
    return S_OK;
}

当我测试布尔值

if (m_StopMesh)
    return S_FALSE;

即使我打电话给AbortMesh()

,这里的值也总是假的
if (m_StopMesh)
        return S_FALSE;

 MessageBox(NULL,aMessage,L"Test",NULL);

 if (m_StopMesh) // here the value is changed to true 
        return S_FALSE;

3 个答案:

答案 0 :(得分:3)

非确定性线程堕胎(与Thread.Abort一样)是一种非常糟糕的做法。问题是,当工作不知道可以停止工作时,这是唯一允许您停止工作的做法。

我知道.NET中没有库或框架允许编写线程代码,允许您运行任意任务并随时中止它而不会产生可怕的后果。

所以,当你决定使用一些同步技术手动中止时,你就完全写了。

<强>解决方案

1)最简单的一个是使用已经建议的易变的布尔变量:

C#

public void AbortMesh()
        { 
            if (currMeshStruct.Value.MeshThread != null && currMeshStruct.Value.MeshThread.IsAlive)
            {                
                MeshCreator.CancelMesh();
            }
        }

C ++ / CLI

public ref class MeshCreator
{

    private:
        volatile System::Boolean m_StopMesh;
    ...
}

STDMETHODIMP MeshCreator::CancelMesh(void)
{
    this->m_StopMesh = TRUE;
    return S_OK;
}

void MeshCreator::ProcessMesh(void)
{
    Int32 processedParts = 0;

    while(processedParts != totalPartsToProcess)
    {
        ContinueProcessing(processedParts);
        processedParts++;

        if (this->m_StopMesh)
        {
            this->MakeCleanup();
            MessageBox(NULL,aMessage,L"Test",NULL);
        }      
    }

}

如果您在CancelMesh调用后没有对线程完成做出任何假设,则此类代码不应要求任何同步 - 它不是即时的,可能需要不同的时间。

我不知道为什么使用volatile对你没有帮助,但是你可以检查一下:

  1. 您确定MeshCreator.CancelMesh();方法调用确实发生了吗?
  2. 您确定在实际处理开始之前正确初始化了m_StopMesh吗?
  3. 您确定经常检查ProcessMesh内的变量,以便从您的工作人员那里获得不错的响应时间,而不是期待瞬间发生的事情吗?
  4. 2)此外,如果您使用.NET 4或更高版本,您也可以尝试使用CancellationToken-CancellationTokenSource model。它最初设计用于处理Tasks模型,但适用于标准线程。它不会真正简化您的代码,但考虑到处理代码的异步性质可能会简化将来与TPL的集成

     CancellationTokenSource cancTokenSource = new CancellationTokenSource();
     CancellationToken cancToken = cancTokenSource.Token;
    
     Thread thread = new Thread(() =>
     {
         Int32 iteration = 0;
         while (true)
         {
             Console.WriteLine("Iteration {0}", iteration);
             iteration++;
             Thread.Sleep(1000);
             if (cancToken.IsCancellationRequested)
                 break;
          }
      });
    
      thread.Start();
    
      Console.WriteLine("Press any key to cancel...");
      Console.ReadKey();
      cancTokenSource.Cancel();
    

    3)您可能希望阅读有关interlocked classmonitor locksautoresetevents和其他同步的信息,但此应用程序实际上并不需要它们

    修改

    嗯,我不知道它是如何无法帮助的(这不是best的想法,但应该适用于这种情况),所以我稍后会尝试模拟你的应用并检查问题 - 可能与MSVC和CSC如何处理volatile说明符有关。

    现在尝试在您的应用中使用Interlocked读写:

    public ref class MeshCreator
    {
    
        private:
            System::Boolean m_StopMesh;
        ...
    }
    
    STDMETHODIMP MeshCreator::CancelMesh(void)
    {
        Interlocked::Exchange(%(this->m_StopMesh), true);
        return S_OK;
    }
    
    void MeshCreator::ProcessMesh(void)
    {
        Int32 processedParts = 0;
    
        while(processedParts != totalPartsToProcess)
        {
            ContinueProcessing(processedParts);
            processedParts++;
    
            if (Interlocked::Read(%(this->m_StopMesh))
            {
                this->MakeCleanup();
                MessageBox(NULL,aMessage,L"Test",NULL);
            }      
        }
    
    }
    

    P.S。:你能发布实际处理数据并检查变量的代码(我不是指你的全网格计算方法,只是它的主要阶段和元素)?

    编辑:至少它清楚系统是关于什么

    您的子进程可能没有足够快地消灭。阅读this SO thread about process killing

    P.S。:并编辑您的问题以更清楚地描述您的系统和问题。对于错误或不完整的问题,很难得到正确的答案。

答案 1 :(得分:1)

  

我使用线程启动了c ++进程并且运行正常。

如果要跨进程边界进行通信,则需要使用某种跨进程通信。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx

我发现Named Pipes方便易用。

<强>更新

您的评论澄清了C ++代码正在进行中运行。

我建议ManualResetEvent。有关线程同步(以及一般的线程)的精彩概述,请查看http://www.albahari.com/threading/

答案 2 :(得分:1)

尝试在字段m_StopMesh:

之前放置volatile
volatile BOOL m_StopMesh;