检测线程内布尔值的变化
本文关键字:变化 布尔值 线程 检测 | 更新日期: 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
没有帮助你,但是有几个时刻你可以检查:
- 你确定
MeshCreator.CancelMesh();
方法调用实际上发生了吗? 你确定m_StopMesh在实际处理开始之前被正确初始化了吗? - 你确定你检查
ProcessMesh
内部的变量经常足够有体面的响应时间从你的工人,而不是期待一些瞬间?
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/