Monitor和ReaderWriterLockSlim无法正常工作

时间:2013-04-27 20:01:01

标签: visual-studio c++-cli

我尝试实现一个典型的线程应用程序,其中一个线程询问设备是否有数据可用,将数据复制到自己的内存并将事件发送到数据可用的主线程。主线程将数据复制到自己的内存中并将其显示在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复制数据。

如果有人能在这种情况下提供帮助,那就太好了。

1 个答案:

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

正如您所看到的那样,写入和读出是受控的,它适用于监视器。