2013-04-27 29 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"); 
} 

正如你看到寫入和讀出被控制,它適用於監視器。