检测线程内布尔值的变化

本文关键字:变化 布尔值 线程 检测 | 更新日期: 2023-09-27 18:10:30

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

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

Thread.Abort()从我读过的大量文章来看是邪恶的主题

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

我的问题是,即使我设置这个值为真,它没有改变,仍然等于假在c++代码。然而,当我显示一个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;

这里的值总是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;

检测线程内布尔值的变化

不确定的线程终止(如thread . abort)是一个非常糟糕的做法。问题是,这是唯一允许您在工作不知道它可以被停止时停止工作的实践。

据我所知,在。net中没有一个库或框架允许编写线程代码,允许你在任何时候运行任意任务并终止它,而不会产生可怕的后果。

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

<<p> 解决方案/strong>:

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内部的变量经常足够有体面的响应时间从你的工人,而不是期待一些瞬间?
2)如果你使用。net 4或更高版本,你也可以尝试使用CancellationToken-CancellationTokenSource模型。它最初被设计为与任务模型一起工作,但与标准线程一起工作也很好。它不会真正简化你的代码,但考虑到你的处理代码的异步特性可能会简化未来与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)你可能想读一下互锁类、监视器锁、autoreseteevents和其他同步,但它们实际上在这个应用程序中是不需要的

编辑:

嗯,我不知道它怎么帮不上忙(这不是最好的主意,但应该适用于这样的场景),所以我以后会尝试模拟你的应用程序并检查问题-可能它与MSVC和CSC如何处理volatile说明符有关。

现在尝试在你的应用程序中使用互锁读写:

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);
        }      
    }
}

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

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

有可能你的子进程没有足够快地被消灭。阅读关于进程终止的SO线程。

注:修改你的问题,更清楚地描述你的系统和问题。对于一个错误或不完整的问题,很难找到正确的答案。

尝试将volatile放在字段m_StopMesh:

volatile BOOL m_StopMesh;

我使用一个线程启动c++进程,它工作得很好。

如果你想跨进程边界进行通信,你需要使用某种形式的跨进程通信。

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

我发现Named Pipes方便易用。

你的评论澄清了c++代码正在进程内运行。

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