我尝试实现一个典型的线程应用程序,其中一个线程询问设备是否有数据可用,将数据复制到自己的内存并将事件发送到数据可用的主线程。主线程将数据复制到自己的内存中并将其显示在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”为false,因此调用“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复制数据。
如果有人能在这种情况下提供帮助,那就太好了。
答案 0 :(得分:0)
我找到了一个带有bool标志的解决方案。 Th标志被称为“System :: Boolean m_bCanWriteData;”并将以这种方式用于“Work :: checkDataIsAvailable()”和“Work :: getData(...)”。
System::Void Work::checkDataIsAvailable()
{
while ( ( Thread::CurrentThread->ThreadState & Threading::ThreadState::Running) == Threading::ThreadState::Running )
{
m_WaitForDoCheckDataIsAvailableHandle->WaitOne();
#ifdef Use_Monitor
Monitor::Enter(m_LockData);
#endif
#ifdef Use_RW_Lock
m_rwlock->EnterWriteLock();
#endif
if ( m_bCanWriteData )
{
m_bCanWriteData = false;
m_Data = m_ValueGenerator->getData();
debugOutput("Work::checkDataIsAvailable() -> Data length = " + m_Data->Length);
if ( nullptr != OnRetrievedData)
{
OnRetrievedData();
}
}
#ifdef Use_RW_Lock
m_rwlock->ExitWriteLock();
#endif
#ifdef Use_Monitor
Monitor::Exit(m_LockData);
#endif
}
}
System::Void Work::getData(array<System::Int32>^% data)
{
debugOutput("Work::getData() START");
#ifdef Use_Monitor
Monitor::Enter(m_LockData);
debugOutput("Work::getData() + Monitor::Enter");
#endif
#ifdef Use_RW_Lock
m_rwlock->EnterReadLock();
#endif
m_WaitForDoCheckDataIsAvailableHandle->Reset(); // Block the thread method.
debugOutput("Work::getData() -> Data length = " + m_Data->Length);
data = m_Data;
m_bCanWriteData = true;
if ( m_bIsRunning )
{
m_WaitForDoCheckDataIsAvailableHandle->Set(); // Start the thread method.
}
#ifdef Use_RW_Lock
m_rwlock->EnterReadLock();
#endif
#ifdef Use_Monitor
Monitor::Exit(m_LockData);
#endif
debugOutput("Work::getData() END");
}
正如您所看到的那样,写入和读出是受控的,它适用于监视器。