繁体   English   中英

C ++ / MFC / ATL线程安全的字符串读取/写入

[英]C++/MFC/ATL Thread-Safe String read/write

我有一个带有启动线程的MFC类,这些线程需要修改主类的CString成员。

我讨厌互斥锁,因此必须有更简单的方法来做到这一点。

我正在考虑使用boost.org库或atl :: atomic或shared_ptr变量。

读取和写入字符串并保持线程安全的最佳方法是什么?

class MyClass
{
   public:
      void        MyClass();
      static UINT MyThread(LPVOID pArg);
      CString     m_strInfo;
};

void MyClass::MyClass()
{
    AfxBeginThread(MyThread, this);
    CString strTmp=m_strInfo; // this may cause crash
}

UINT MyClass::MyThread(LPVOID pArg)
{
     MyClass pClass=(MyClass*)pArd;
     pClass->m_strInfo=_T("New Value"); // non thread-safe change
}

据MSDN称,shared_ptr自动运行https://msdn.microsoft.com/en-us/library/bb982026.aspx

那么这是更好的方法吗?

#include <memory>
class MyClass
{
   public:
      void        MyClass();
      static UINT MyThread(LPVOID pArg);
      std::shared_ptr<CString>    m_strInfo;  // ********
};

void MyClass::MyClass()
{
    AfxBeginThread(MyThread, this);
    CString strTmp=m_strInfo; // this may cause crash
}

UINT MyClass::MyThread(LPVOID pArg)
{
     MyClass pClass=(MyClass*)pArd;
     shared_ptr<CString> newValue(new CString());

     newValue->SetString(_T("New Value"));
     pClass->m_strInfo=newValue; // thread-safe change?
}

您可以实现某种无锁方式来实现该目的,但这取决于您如何使用MyClass和线程。 如果您的线程正在处理某些数据,并且在处理完之后,则需要更新MyClass,然后考虑将字符串数据放入其他某个类,例如:

struct StringData {
    CString     m_strInfo;
};

然后在您的MyClass中:

class MyClass
{
   public:
      void        MyClass();
      static UINT MyThread(LPVOID pArg);
      StringData*     m_pstrData;
      StringData*     m_pstrDataForThreads;
};

现在,这个想法是在你的即。 主线程代码使用m_pstrData,但是您需要使用原子存储指向它的本地指针,即:

void MyClass::MyClass()
{
    AfxBeginThread(MyThread, this);

    StringData*  m_pstrDataTemp = ATOMIC_READ(m_pstrData);
    if ( m_pstrDataTemp )
        CString strTmp=m_pstrDataTemp->m_strInfo; // this may NOT cause crash
}

一旦你的线程完成数据处理,并且要更新的字符串,你会原子分配m_pstrDataForThreadsm_pstrData ,并分配新m_pstrDataForThreads

问题在于如何安全地删除m_pstrData,我想您可以在此处使用std :: shared_ptr。

最后,它看起来有点复杂,并且IMO确实不值得付出努力,至少很难确定这是否真的是线程安全的,以及何时代码变得更加复杂-它仍然是线程安全的。 同样,这是针对单个工作线程的情况,您说您有多个线程。 这就是为什么关键部分是起点的原因,如果它太慢,则考虑使用无锁方法。

顺便说一句。 根据字符串数据的更新频率,您还可以考虑使用PostMessage将指向新字符串的指针安全地传递到主线程。

[编辑]

ATOMIC_MACRO不存在,它只是一个占位符以使其编译使用,即。 c ++ 11原子,示例如下:

#include <atomic>
...
std::atomic<uint64_t> sharedValue(0);
sharedValue.store(123, std::memory_order_relaxed);          // atomically store
uint64_t ret = sharedValue.load(std::memory_order_relaxed); // atomically read
std::cout << ret;

我本可以通过SetStrInfo保护变量来使用更简单的方法:

void SetStrInfo(const CString& str)
{
    [Lock-here]
    m_strInfo = str;
    [Unlock-here]
}

对于锁定和解锁,我们可以使用CCriticalSection (类的成员),或将其包装在CSingleLock RAII周围。 出于性能原因,我们可能还会使用苗条的读取器编写器锁 (使用RAII进行包装-写一个简单的类)。 我们也可以使用更新的C ++技术进行RAII锁定/解锁。

称我为老式学校,但对我而言, std名称空间具有复杂的选项集-不适用于所有事物,也不适合所有人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM