我尝试实现一个典型的线程应用程序,其中一个线程询问设备数据是否可用,将数据复制到自己的内存中,并向主线程发送数据可用的事件。主线程将数据复制到自己的内存中并显示在 GUI 上。
为此,我将 Visual Studio 2012 和 C++/CLI 与 Winforms 一起使用。
有一个类“Work”包含线程方法“checkDataIsAvailable”。“Work”类实现了一个带有委托“OnRetrievedData”的接口(而不是抽象类),该委托作为事件工作并在“Form1”中调用“BeginInvoke”以具有异步行为。还有一个方法“getData”,主线程可以从“checkDataIsAvailable”线程获取数据。此外,“Work”类尝试从“ValueGenerator”类中获取数据,该类可以代表任何真实设备。我为“工作”类中的“数据”确定了一个关键部分,称为“array^ m_Data;”。问题是“监视器”和“ReaderWriterLockSlim”工作方法都不起作用。使用“监视器”时,GUI 会延迟响应,并且缺少许多更新。使用“ReaderWriterLockSlim”应用程序崩溃。并且在不保存关键部分的情况下,应用程序可以正常工作。但我不知道原因,因为我确定必须保存数据。
我想简化源代码并强调重要的事情。
最重要的是线程方法:
System::Void Work::checkDataIsAvailable()
{
while ( ( Thread::CurrentThread->ThreadState & Threading::ThreadState::Running) == Threading::ThreadState::Running )
{
m_WaitForDoCheckDataIsAvailableHandle->WaitOne();
//Monitor::Enter(m_LockData);
m_rwlock->EnterWriteLock();
m_Data = m_ValueGenerator->getData();
m_rwlock->ExitWriteLock();
//Monitor::Exit(m_LockData);
if ( nullptr != OnRetrievedData)
{
OnRetrievedData();
}
}
}
在这里您可以看到从“ValueGenerator”到变量 m_Data 的复制过程。在我看来,这是一个关键部分。然后将发送事件“OnRetrievedData”,表明数据可用。
此事件将获得 Form1:
System::Void Form1::OnAcquisitionUpdate()
{
if(this->InvokeRequired == true)
{
OnAcquisitionUpdateDelegate^ onAcquisitionUpdateDelegate = gcnew OnAcquisitionUpdateDelegate(this, &Form1::OnAcquisitionUpdate);
this->BeginInvoke(onAcquisitionUpdateDelegate);
//this->Invoke(onAcquisitionUpdateDelegate);
}
else
{
if ( nullptr != m_Work )
{
//Thread::Sleep(5000);
array<System::Int32>^ data;
m_Work->getData(data);
dataResult_label->Text = data->Length.ToString();
}
}
}
“Form1::OnAcquisitionUpdate”通过“BeginInvoke”将其更改为主线程并再次调用“Form1::OnAcquisitionUpdate”,但现在“InvokeRequired”为假,因此调用“Work”类从主线程获取数据。
System::Void Work::getData(array<System::Int32>^% data)
{
//Monitor::Enter(m_LockData);
m_rwlock->EnterReadLock();
Console::WriteLine(" getData() -> Data length = {0}", m_Data->Length);
data = m_Data;
m_rwlock->EnterReadLock();
//Monitor::Exit(m_LockData);
}
在这里,我看到下一个关键部分,将为调用者 Form1 复制数据。
如果有人可以在这种情况下提供帮助,那就太好了。