检测Thread内部的布尔值更改 [英] Detect Boolean value changes inside Thread

查看:106
本文介绍了检测Thread内部的布尔值更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



有时候我需要取消该主题,这里是问题:



> Thread.Abort()是从我在
阅读的文章中得到的。



做到这一点是使用一个bool和检查它的值是定期。



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

  public void AbortMesh()
{
if(currMeshStruct.Value.MeshThread != null&& currMeshStruct.Value.MeshThread.IsAlive)
{
//这里是我的c ++对象和取消网格用于设置bool为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,LTest,NULL);

if(m_StopMesh)//这里的值更改为true
return S_FALSE;


解决方案

非确定性线程中止中止)是一个非常糟糕的做法。问题是,这是唯一的做法,允许你停止工作,当工作不知道它可以停止。



在.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,LTest,NULL);
}
}

}

不应该要求任何同步,如果在 CancelMesh 调用后没有对线程完成做出任何假设 - 它不是瞬时的,并且可能需要不同的时间量发生。 p>

我不知道为什么使用 volatile 没有帮助你,但有几分钟检查:


  1. 您确定 MeshCreator.CancelMesh(); 方法调用

  2. 您确定在实际处理开始之前已正确初始化m_StopMesh吗?

  3. 您确定要检查<












$ b

2)另外,如果你使用.NET 4或更高版本,你还可以尝试使用 CancellationToken-CancellationTokenSource模型。它最初设计为使用Tasks模型,但适用于标准线程。它不会真正简化您的代码,但考虑到处理代码的异步性质可能会简化未来集成 TPL

  CancellationTokenSource cancTokenSource = new CancellationTokenSource ); 
CancellationToken cancToken = cancTokenSource.Token;

线程线程= new Thread(()=>
{
Int32 iteration = 0;
while(true)
{
Console.WriteLine(Iteration {0},iteration);
iteration ++;
Thread.Sleep(1000);
if(cancToken.IsCancellationRequested)
break;
}
});

thread.Start();

Console.WriteLine(按任意键取消...);
Console.ReadKey();
cancTokenSource.Cancel();

3)您可能想阅读关于互锁类监视锁 autoresetevents 和其他同步,但这些应用程序实际上并不需要。



EDIT:



好吧,我不知道如何不能帮助(这不是最好的想法,但应该适用于这样的场景),所以我会尝试以后模拟你的应用程序,并检查问题 - 可能它与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 ,LTest,NULL);
}
}

}

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



编辑:至少清除系统所关联的



这可能是您的子进程没有足够的消灭速度。请阅读此SO线程关于进程杀死的信息



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

I have a c++ dll function that i want to run inside the C# thread.

Some times I need to cancel that thread, and here is the issue :

Thread.Abort() is evil from the multitude of articles I've read on the topic

The only way to do that was to use a bool and check it's value periodically.

My problem that even i set this value to true it didn't change and still equal to false in c++ code. However when I show a MessageBox that value changed and it works fine. Any ideas why that value changed only when the MessageBox showed and please tell me how to fix that issue. 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;
}

when I test the boolean value

if (m_StopMesh)
    return S_FALSE;

The value here is always false even i call 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;

解决方案

The non-deterministic thread abortion (like with Thread.Abort) is a really bad practice. The problem is that it is the only practice that allows you to stop your job when job does not know that it could be stopped.

There is no library or framework in .NET I know of that allows to write threaded code that could allow you to run an arbitrary task and abort it at any time without dire consequences.

So, you was completely write when you decided to use manual abort using some synchronization technique.

Solutions:

1) The simplest one is using of a volatile Boolean variable as it was already suggested:

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

}

Such code should not require any synchronization if you do not make any assumptions on completion of thread after the CancelMesh call - it is not instantaneous and may take variable amount of time to happen.

I don't know why the use of the volatile didn't help you, but there are few moments you could check:

  1. Are you sure that the MeshCreator.CancelMesh(); method call actually happen?
  2. Are you sure that m_StopMesh is properly initialized before the actual processing begins?
  3. Are you sure that you check the variable inside the ProcessMesh often enough to have decent response time from your worker and not expecting something instantaneous?

2)Also if you use .NET 4 or higher you could also try to use the CancellationToken-CancellationTokenSource model. It was initially designed to work with Tasks model but works well with standard threads. It won't really simplify your code but taking into an account the async nature of your processing code will possibly simplify future integration with 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) You may want to read about interlocked class,monitor locks, autoresetevents and other synchronization, but they are not actually needed in this application

EDIT:

Well, I don't know how it couldn't help(it is not the best idea, but should work for such a scenario), so I'll try later to mock your app and check the issue - possibly it has something to do with how MSVC and CSC handle volatile specifier.

For now try to use Interlocked reads and writes in your app:

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.: Can you post the code that actually processes the data and checks the variable(I don't mean your full meshes calculations method, just its main stages and elements)?

EDIT: AT LEAST IT'S CLEAR WHAT THE SYSTEM IS ABOUT

It is possible that your child processes are just not exterminated quick enough. Read this SO thread about process killing.

P.S.: And edit your question to more clearly describe your system and problem. It is difficult to get the right answer to a wrong or incomplete question.

这篇关于检测Thread内部的布尔值更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆