2013-04-27 38 views
0

我试图实现一个典型的线程应用程序,其中一个线程询问设备是否有数据可用,将数据复制到其自己的内存并将数据发送到数据可用的主线程。主线程将数据复制到其自己的内存并将其显示在GUI上。监视器和ReaderWriterLockSlim不起作用

为此,我使用Visual Studio 2012和C++/CLI与Winforms。

有一个类“Work”,它包含线程方法“checkDataIsAvailable”。 “Work”类实现了一个接口(相当于一个抽象类),它具有一个作为事件的代理“OnRetrievedData”,并在“Form1”中调用“BeginInvoke”以实现异步行为。还有一个方法“getData”,其中主线程可以从“checkDataIsAvailable”线程获取数据。此外,“Work”类尝试从类“ValueGenerator”中获取可能代表任何实际设备的数据。我在“Work”类中为“数据”标识了一个称为“array^m_Data;”的关键部分。问题是“Monitor”和“ReaderWriterLockSlim”工作方法都无法正常工作。 使用“监视器”时,图形用户界面出现延迟响应,许多更新丢失。 使用“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的下一个关键部分。

这将是很好,如果有人可以帮助在这种情况下。

+1

这是很多代码。你能否简化它,只有与你的问题实际相关的代码才被包含在内?另外,应用程序究竟如何崩溃?如果您收到异常,它的消息和堆栈跟踪是什么? – svick 2013-04-27 20:37:34

+0

您正在以非常高的速率生成数据,而没有对它进行任何限制。你的锁定是完全无效的。使用.NET BlockingCollection <>类。 – 2013-04-27 23:05:50

回答

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

正如你看到写入和读出被控制,它适用于监视器。